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

UsersController::signMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
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