Passed
Push — master ( 3d1c78...1b4788 )
by Blizzz
20:40 queued 05:15
created

UsersController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 35
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 16
nc 1
nop 17
dl 0
loc 35
rs 9.7333
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright Copyright (c) 2016, ownCloud, Inc.
7
 *
8
 * @author Arthur Schiwon <[email protected]>
9
 * @author Bjoern Schiessle <[email protected]>
10
 * @author Christoph Wurst <[email protected]>
11
 * @author Daniel Kesselberg <[email protected]>
12
 * @author GretaD <[email protected]>
13
 * @author Joas Schilling <[email protected]>
14
 * @author John Molakvoæ (skjnldsv) <[email protected]>
15
 * @author Morris Jobke <[email protected]>
16
 * @author Robin Appelman <[email protected]>
17
 * @author Roeland Jago Douma <[email protected]>
18
 *
19
 * @license AGPL-3.0
20
 *
21
 * This code is free software: you can redistribute it and/or modify
22
 * it under the terms of the GNU Affero General Public License, version 3,
23
 * as published by the Free Software Foundation.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
 * GNU Affero General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Affero General Public License, version 3,
31
 * along with this program. If not, see <http://www.gnu.org/licenses/>
32
 *
33
 */
34
35
// FIXME: disabled for now to be able to inject IGroupManager and also use
36
// getSubAdmin()
37
38
namespace OCA\Settings\Controller;
39
40
use InvalidArgumentException;
41
use OC\AppFramework\Http;
42
use OC\Encryption\Exceptions\ModuleDoesNotExistsException;
43
use OC\ForbiddenException;
44
use OC\Group\Manager as GroupManager;
45
use OC\KnownUser\KnownUserService;
46
use OC\L10N\Factory;
47
use OC\Security\IdentityProof\Manager;
48
use OC\User\Manager as UserManager;
49
use OCA\Settings\BackgroundJobs\VerifyUserData;
50
use OCA\Settings\Events\BeforeTemplateRenderedEvent;
51
use OCA\User_LDAP\User_Proxy;
52
use OCP\Accounts\IAccount;
53
use OCP\Accounts\IAccountManager;
54
use OCP\Accounts\PropertyDoesNotExistException;
55
use OCP\App\IAppManager;
56
use OCP\AppFramework\Controller;
57
use OCP\AppFramework\Http\DataResponse;
58
use OCP\AppFramework\Http\JSONResponse;
59
use OCP\AppFramework\Http\TemplateResponse;
60
use OCP\BackgroundJob\IJobList;
61
use OCP\Encryption\IManager;
62
use OCP\EventDispatcher\IEventDispatcher;
63
use OCP\IConfig;
64
use OCP\IGroupManager;
65
use OCP\IL10N;
66
use OCP\IRequest;
67
use OCP\IUser;
68
use OCP\IUserManager;
69
use OCP\IUserSession;
70
use OCP\L10N\IFactory;
71
use OCP\Mail\IMailer;
72
use function in_array;
73
74
class UsersController extends Controller {
75
	/** @var UserManager */
76
	private $userManager;
77
	/** @var GroupManager */
78
	private $groupManager;
79
	/** @var IUserSession */
80
	private $userSession;
81
	/** @var IConfig */
82
	private $config;
83
	/** @var bool */
84
	private $isAdmin;
85
	/** @var IL10N */
86
	private $l10n;
87
	/** @var IMailer */
88
	private $mailer;
89
	/** @var Factory */
90
	private $l10nFactory;
91
	/** @var IAppManager */
92
	private $appManager;
93
	/** @var IAccountManager */
94
	private $accountManager;
95
	/** @var Manager */
96
	private $keyManager;
97
	/** @var IJobList */
98
	private $jobList;
99
	/** @var IManager */
100
	private $encryptionManager;
101
	/** @var KnownUserService */
102
	private $knownUserService;
103
	/** @var IEventDispatcher */
104
	private $dispatcher;
105
106
107
	public function __construct(
108
		string $appName,
109
		IRequest $request,
110
		IUserManager $userManager,
111
		IGroupManager $groupManager,
112
		IUserSession $userSession,
113
		IConfig $config,
114
		bool $isAdmin,
115
		IL10N $l10n,
116
		IMailer $mailer,
117
		IFactory $l10nFactory,
118
		IAppManager $appManager,
119
		IAccountManager $accountManager,
120
		Manager $keyManager,
121
		IJobList $jobList,
122
		IManager $encryptionManager,
123
		KnownUserService $knownUserService,
124
		IEventDispatcher $dispatcher
125
	) {
126
		parent::__construct($appName, $request);
127
		$this->userManager = $userManager;
0 ignored issues
show
Documentation Bug introduced by
$userManager is of type OCP\IUserManager, but the property $userManager was declared to be of type OC\User\Manager. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
128
		$this->groupManager = $groupManager;
0 ignored issues
show
Documentation Bug introduced by
$groupManager is of type OCP\IGroupManager, but the property $groupManager was declared to be of type OC\Group\Manager. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
129
		$this->userSession = $userSession;
130
		$this->config = $config;
131
		$this->isAdmin = $isAdmin;
132
		$this->l10n = $l10n;
133
		$this->mailer = $mailer;
134
		$this->l10nFactory = $l10nFactory;
0 ignored issues
show
Documentation Bug introduced by
$l10nFactory is of type OCP\L10N\IFactory, but the property $l10nFactory was declared to be of type OC\L10N\Factory. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
135
		$this->appManager = $appManager;
136
		$this->accountManager = $accountManager;
137
		$this->keyManager = $keyManager;
138
		$this->jobList = $jobList;
139
		$this->encryptionManager = $encryptionManager;
140
		$this->knownUserService = $knownUserService;
141
		$this->dispatcher = $dispatcher;
142
	}
143
144
145
	/**
146
	 * @NoCSRFRequired
147
	 * @NoAdminRequired
148
	 *
149
	 * Display users list template
150
	 *
151
	 * @return TemplateResponse
152
	 */
153
	public function usersListByGroup(): TemplateResponse {
154
		return $this->usersList();
155
	}
156
157
	/**
158
	 * @NoCSRFRequired
159
	 * @NoAdminRequired
160
	 *
161
	 * Display users list template
162
	 *
163
	 * @return TemplateResponse
164
	 */
165
	public function usersList(): TemplateResponse {
166
		$user = $this->userSession->getUser();
167
		$uid = $user->getUID();
168
169
		\OC::$server->getNavigationManager()->setActiveEntry('core_users');
170
171
		/* SORT OPTION: SORT_USERCOUNT or SORT_GROUPNAME */
172
		$sortGroupsBy = \OC\Group\MetaData::SORT_USERCOUNT;
173
		$isLDAPUsed = false;
174
		if ($this->config->getSystemValue('sort_groups_by_name', false)) {
175
			$sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME;
176
		} else {
177
			if ($this->appManager->isEnabledForUser('user_ldap')) {
178
				$isLDAPUsed =
179
					$this->groupManager->isBackendUsed('\OCA\User_LDAP\Group_Proxy');
180
				if ($isLDAPUsed) {
181
					// LDAP user count can be slow, so we sort by group name here
182
					$sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME;
183
				}
184
			}
185
		}
186
187
		$canChangePassword = $this->canAdminChangeUserPasswords();
188
189
		/* GROUPS */
190
		$groupsInfo = new \OC\Group\MetaData(
191
			$uid,
192
			$this->isAdmin,
193
			$this->groupManager,
194
			$this->userSession
195
		);
196
197
		$groupsInfo->setSorting($sortGroupsBy);
198
		[$adminGroup, $groups] = $groupsInfo->get();
199
200
		if (!$isLDAPUsed && $this->appManager->isEnabledForUser('user_ldap')) {
201
			$isLDAPUsed = (bool)array_reduce($this->userManager->getBackends(), function ($ldapFound, $backend) {
202
				return $ldapFound || $backend instanceof User_Proxy;
203
			});
204
		}
205
206
		$disabledUsers = -1;
207
		$userCount = 0;
208
209
		if (!$isLDAPUsed) {
210
			if ($this->isAdmin) {
211
				$disabledUsers = $this->userManager->countDisabledUsers();
212
				$userCount = array_reduce($this->userManager->countUsers(), function ($v, $w) {
213
					return $v + (int)$w;
214
				}, 0);
215
			} else {
216
				// User is subadmin !
217
				// Map group list to names to retrieve the countDisabledUsersOfGroups
218
				$userGroups = $this->groupManager->getUserGroups($user);
219
				$groupsNames = [];
220
221
				foreach ($groups as $key => $group) {
222
					// $userCount += (int)$group['usercount'];
223
					array_push($groupsNames, $group['name']);
224
					// we prevent subadmins from looking up themselves
225
					// so we lower the count of the groups he belongs to
226
					if (array_key_exists($group['id'], $userGroups)) {
227
						$groups[$key]['usercount']--;
228
						$userCount -= 1; // we also lower from one the total count
229
					}
230
				}
231
				$userCount += $this->userManager->countUsersOfGroups($groupsInfo->getGroups());
232
				$disabledUsers = $this->userManager->countDisabledUsersOfGroups($groupsNames);
233
			}
234
235
			$userCount -= $disabledUsers;
236
		}
237
238
		$disabledUsersGroup = [
239
			'id' => 'disabled',
240
			'name' => 'Disabled users',
241
			'usercount' => $disabledUsers
242
		];
243
244
		/* QUOTAS PRESETS */
245
		$quotaPreset = $this->parseQuotaPreset($this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB'));
246
		$defaultQuota = $this->config->getAppValue('files', 'default_quota', 'none');
247
248
		$event = new BeforeTemplateRenderedEvent();
249
		$this->dispatcher->dispatch('OC\Settings\Users::loadAdditionalScripts', $event);
250
		$this->dispatcher->dispatchTyped($event);
251
252
		/* LANGUAGES */
253
		$languages = $this->l10nFactory->getLanguages();
254
255
		/* FINAL DATA */
256
		$serverData = [];
257
		// groups
258
		$serverData['groups'] = array_merge_recursive($adminGroup, [$disabledUsersGroup], $groups);
259
		// Various data
260
		$serverData['isAdmin'] = $this->isAdmin;
261
		$serverData['sortGroups'] = $sortGroupsBy;
262
		$serverData['quotaPreset'] = $quotaPreset;
263
		$serverData['userCount'] = $userCount;
264
		$serverData['languages'] = $languages;
265
		$serverData['defaultLanguage'] = $this->config->getSystemValue('default_language', 'en');
266
		$serverData['forceLanguage'] = $this->config->getSystemValue('force_language', false);
267
		// Settings
268
		$serverData['defaultQuota'] = $defaultQuota;
269
		$serverData['canChangePassword'] = $canChangePassword;
270
		$serverData['newUserGenerateUserID'] = $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes';
271
		$serverData['newUserRequireEmail'] = $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes';
272
		$serverData['newUserSendEmail'] = $this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes';
273
274
		return new TemplateResponse('settings', 'settings-vue', ['serverData' => $serverData]);
275
	}
276
277
	/**
278
	 * @param string $key
279
	 * @param string $value
280
	 *
281
	 * @return JSONResponse
282
	 */
283
	public function setPreference(string $key, string $value): JSONResponse {
284
		$allowed = ['newUser.sendEmail'];
285
		if (!in_array($key, $allowed, true)) {
286
			return new JSONResponse([], Http::STATUS_FORBIDDEN);
287
		}
288
289
		$this->config->setAppValue('core', $key, $value);
290
291
		return new JSONResponse([]);
292
	}
293
294
	/**
295
	 * Parse the app value for quota_present
296
	 *
297
	 * @param string $quotaPreset
298
	 * @return array
299
	 */
300
	protected function parseQuotaPreset(string $quotaPreset): array {
301
		// 1 GB, 5 GB, 10 GB => [1 GB, 5 GB, 10 GB]
302
		$presets = array_filter(array_map('trim', explode(',', $quotaPreset)));
303
		// Drop default and none, Make array indexes numerically
304
		return array_values(array_diff($presets, ['default', 'none']));
305
	}
306
307
	/**
308
	 * check if the admin can change the users password
309
	 *
310
	 * The admin can change the passwords if:
311
	 *
312
	 *   - no encryption module is loaded and encryption is disabled
313
	 *   - encryption module is loaded but it doesn't require per user keys
314
	 *
315
	 * The admin can not change the passwords if:
316
	 *
317
	 *   - an encryption module is loaded and it uses per-user keys
318
	 *   - encryption is enabled but no encryption modules are loaded
319
	 *
320
	 * @return bool
321
	 */
322
	protected function canAdminChangeUserPasswords(): bool {
323
		$isEncryptionEnabled = $this->encryptionManager->isEnabled();
324
		try {
325
			$noUserSpecificEncryptionKeys = !$this->encryptionManager->getEncryptionModule()->needDetailedAccessList();
326
			$isEncryptionModuleLoaded = true;
327
		} catch (ModuleDoesNotExistsException $e) {
328
			$noUserSpecificEncryptionKeys = true;
329
			$isEncryptionModuleLoaded = false;
330
		}
331
		$canChangePassword = ($isEncryptionModuleLoaded && $noUserSpecificEncryptionKeys)
332
			|| (!$isEncryptionModuleLoaded && !$isEncryptionEnabled);
333
334
		return $canChangePassword;
335
	}
336
337
	/**
338
	 * @NoAdminRequired
339
	 * @NoSubAdminRequired
340
	 * @PasswordConfirmationRequired
341
	 *
342
	 * @param string|null $avatarScope
343
	 * @param string|null $displayname
344
	 * @param string|null $displaynameScope
345
	 * @param string|null $phone
346
	 * @param string|null $phoneScope
347
	 * @param string|null $email
348
	 * @param string|null $emailScope
349
	 * @param string|null $website
350
	 * @param string|null $websiteScope
351
	 * @param string|null $address
352
	 * @param string|null $addressScope
353
	 * @param string|null $twitter
354
	 * @param string|null $twitterScope
355
	 *
356
	 * @return DataResponse
357
	 */
358
	public function setUserSettings(?string $avatarScope = null,
359
									?string $displayname = null,
360
									?string $displaynameScope = null,
361
									?string $phone = null,
362
									?string $phoneScope = null,
363
									?string $email = null,
364
									?string $emailScope = null,
365
									?string $website = null,
366
									?string $websiteScope = null,
367
									?string $address = null,
368
									?string $addressScope = null,
369
									?string $twitter = null,
370
									?string $twitterScope = null
371
	) {
372
		$user = $this->userSession->getUser();
373
		if (!$user instanceof IUser) {
374
			return new DataResponse(
375
				[
376
					'status' => 'error',
377
					'data' => [
378
						'message' => $this->l10n->t('Invalid user')
379
					]
380
				],
381
				Http::STATUS_UNAUTHORIZED
382
			);
383
		}
384
385
		$email = !is_null($email) ? strtolower($email) : $email;
386
		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
387
			return new DataResponse(
388
				[
389
					'status' => 'error',
390
					'data' => [
391
						'message' => $this->l10n->t('Invalid mail address')
392
					]
393
				],
394
				Http::STATUS_UNPROCESSABLE_ENTITY
395
			);
396
		}
397
398
		$userAccount = $this->accountManager->getAccount($user);
399
		$oldPhoneValue = $userAccount->getProperty(IAccountManager::PROPERTY_PHONE)->getValue();
400
401
		$updatable = [
402
			IAccountManager::PROPERTY_AVATAR => ['value' => null, 'scope' => $avatarScope],
403
			IAccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
404
			IAccountManager::PROPERTY_EMAIL => ['value' => $email, 'scope' => $emailScope],
405
			IAccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
406
			IAccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
407
			IAccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
408
			IAccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope],
409
		];
410
		$allowUserToChangeDisplayName = $this->config->getSystemValueBool('allow_user_to_change_display_name', true);
411
		foreach ($updatable as $property => $data) {
412
			if ($allowUserToChangeDisplayName === false
413
				&& in_array($property, [IAccountManager::PROPERTY_DISPLAYNAME, IAccountManager::PROPERTY_EMAIL], true)) {
414
				continue;
415
			}
416
			$property = $userAccount->getProperty($property);
417
			if (null !== $data['value']) {
418
				$property->setValue($data['value']);
419
			}
420
			if (null !== $data['scope']) {
421
				$property->setScope($data['scope']);
422
			}
423
		}
424
425
		try {
426
			$this->saveUserSettings($userAccount);
427
			if ($oldPhoneValue !== $userAccount->getProperty(IAccountManager::PROPERTY_PHONE)->getValue()) {
428
				$this->knownUserService->deleteByContactUserId($user->getUID());
429
			}
430
			return new DataResponse(
431
				[
432
					'status' => 'success',
433
					'data' => [
434
						'userId' => $user->getUID(),
435
						'avatarScope' => $userAccount->getProperty(IAccountManager::PROPERTY_AVATAR)->getScope(),
436
						'displayname' => $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getValue(),
437
						'displaynameScope' => $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getScope(),
438
						'phone' => $userAccount->getProperty(IAccountManager::PROPERTY_PHONE)->getValue(),
439
						'phoneScope' => $userAccount->getProperty(IAccountManager::PROPERTY_PHONE)->getScope(),
440
						'email' => $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue(),
441
						'emailScope' => $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope(),
442
						'website' => $userAccount->getProperty(IAccountManager::PROPERTY_WEBSITE)->getValue(),
443
						'websiteScope' => $userAccount->getProperty(IAccountManager::PROPERTY_WEBSITE)->getScope(),
444
						'address' => $userAccount->getProperty(IAccountManager::PROPERTY_ADDRESS)->getValue(),
445
						'addressScope' => $userAccount->getProperty(IAccountManager::PROPERTY_ADDRESS)->getScope(),
446
						'twitter' => $userAccount->getProperty(IAccountManager::PROPERTY_TWITTER)->getValue(),
447
						'twitterScope' => $userAccount->getProperty(IAccountManager::PROPERTY_TWITTER)->getScope(),
448
						'message' => $this->l10n->t('Settings saved'),
449
					],
450
				],
451
				Http::STATUS_OK
452
			);
453
		} catch (ForbiddenException | InvalidArgumentException | PropertyDoesNotExistException $e) {
454
			return new DataResponse([
455
				'status' => 'error',
456
				'data' => [
457
					'message' => $e->getMessage()
458
				],
459
			]);
460
		}
461
	}
462
	/**
463
	 * update account manager with new user data
464
	 *
465
	 * @throws ForbiddenException
466
	 * @throws InvalidArgumentException
467
	 */
468
	protected function saveUserSettings(IAccount $userAccount): void {
469
		// keep the user back-end up-to-date with the latest display name and email
470
		// address
471
		$oldDisplayName = $userAccount->getUser()->getDisplayName();
472
		if ($oldDisplayName !== $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getValue()) {
473
			$result = $userAccount->getUser()->setDisplayName($userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getValue());
474
			if ($result === false) {
475
				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
476
			}
477
		}
478
479
		$oldEmailAddress = $userAccount->getUser()->getEMailAddress();
480
		$oldEmailAddress = strtolower((string)$oldEmailAddress);
481
		if ($oldEmailAddress !== $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue()) {
482
			// this is the only permission a backend provides and is also used
483
			// for the permission of setting a email address
484
			if (!$userAccount->getUser()->canChangeDisplayName()) {
485
				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
486
			}
487
			$userAccount->getUser()->setEMailAddress($userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue());
488
		}
489
490
		try {
491
			$this->accountManager->updateAccount($userAccount);
492
		} catch (InvalidArgumentException $e) {
493
			if ($e->getMessage() === IAccountManager::PROPERTY_PHONE) {
494
				throw new InvalidArgumentException($this->l10n->t('Unable to set invalid phone number'));
495
			}
496
			if ($e->getMessage() === IAccountManager::PROPERTY_WEBSITE) {
497
				throw new InvalidArgumentException($this->l10n->t('Unable to set invalid website'));
498
			}
499
			throw new InvalidArgumentException($this->l10n->t('Some account data was invalid'));
500
		}
501
	}
502
503
	/**
504
	 * Set the mail address of a user
505
	 *
506
	 * @NoAdminRequired
507
	 * @NoSubAdminRequired
508
	 * @PasswordConfirmationRequired
509
	 *
510
	 * @param string $account
511
	 * @param bool $onlyVerificationCode only return verification code without updating the data
512
	 * @return DataResponse
513
	 */
514
	public function getVerificationCode(string $account, bool $onlyVerificationCode): DataResponse {
515
		$user = $this->userSession->getUser();
516
517
		if ($user === null) {
518
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
519
		}
520
521
		$userAccount = $this->accountManager->getAccount($user);
522
		$cloudId = $user->getCloudId();
523
		$message = 'Use my Federated Cloud ID to share with me: ' . $cloudId;
524
		$signature = $this->signMessage($user, $message);
525
526
		$code = $message . ' ' . $signature;
527
		$codeMd5 = $message . ' ' . md5($signature);
528
529
		switch ($account) {
530
			case 'verify-twitter':
531
				$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):');
532
				$code = $codeMd5;
533
				$type = IAccountManager::PROPERTY_TWITTER;
534
				break;
535
			case 'verify-website':
536
				$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):');
537
				$type = IAccountManager::PROPERTY_WEBSITE;
538
				break;
539
			default:
540
				return new DataResponse([], Http::STATUS_BAD_REQUEST);
541
		}
542
543
		$userProperty = $userAccount->getProperty($type);
544
		$userProperty
545
			->setVerified(IAccountManager::VERIFICATION_IN_PROGRESS)
546
			->setVerificationData($signature);
547
548
		if ($onlyVerificationCode === false) {
549
			$this->accountManager->updateAccount($userAccount);
550
551
			$this->jobList->add(VerifyUserData::class,
552
				[
553
					'verificationCode' => $code,
554
					'data' => $userProperty->getValue(),
555
					'type' => $type,
556
					'uid' => $user->getUID(),
557
					'try' => 0,
558
					'lastRun' => $this->getCurrentTime()
559
				]
560
			);
561
		}
562
563
		return new DataResponse(['msg' => $msg, 'code' => $code]);
564
	}
565
566
	/**
567
	 * get current timestamp
568
	 *
569
	 * @return int
570
	 */
571
	protected function getCurrentTime(): int {
572
		return time();
573
	}
574
575
	/**
576
	 * sign message with users private key
577
	 *
578
	 * @param IUser $user
579
	 * @param string $message
580
	 *
581
	 * @return string base64 encoded signature
582
	 */
583
	protected function signMessage(IUser $user, string $message): string {
584
		$privateKey = $this->keyManager->getKey($user)->getPrivate();
585
		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
586
		return base64_encode($signature);
587
	}
588
}
589