Passed
Push — master ( 0247f2...f657f0 )
by Morris
13:19 queued 11s
created

UsersController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 33
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 15
nc 1
nop 16
dl 0
loc 33
rs 9.7666
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
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bjoern Schiessle <[email protected]>
7
 * @author Christoph Wurst <[email protected]>
8
 * @author Daniel Kesselberg <[email protected]>
9
 * @author GretaD <[email protected]>
10
 * @author Joas Schilling <[email protected]>
11
 * @author John Molakvoæ (skjnldsv) <[email protected]>
12
 * @author Morris Jobke <[email protected]>
13
 * @author Roeland Jago Douma <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program. If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
31
// FIXME: disabled for now to be able to inject IGroupManager and also use
32
// getSubAdmin()
33
//declare(strict_types=1);
34
35
namespace OCA\Settings\Controller;
36
37
use OC\Accounts\AccountManager;
38
use OC\AppFramework\Http;
39
use OC\Encryption\Exceptions\ModuleDoesNotExistsException;
40
use OC\ForbiddenException;
41
use OC\Group\Manager as GroupManager;
42
use OC\L10N\Factory;
43
use OC\Security\IdentityProof\Manager;
44
use OC\User\Manager as UserManager;
45
use OCA\FederatedFileSharing\FederatedShareProvider;
46
use OCA\Settings\BackgroundJobs\VerifyUserData;
47
use OCA\Settings\Events\BeforeTemplateRenderedEvent;
48
use OCA\User_LDAP\User_Proxy;
49
use OCP\App\IAppManager;
50
use OCP\AppFramework\Controller;
51
use OCP\AppFramework\Http\DataResponse;
52
use OCP\AppFramework\Http\JSONResponse;
53
use OCP\AppFramework\Http\TemplateResponse;
54
use OCP\BackgroundJob\IJobList;
55
use OCP\Encryption\IManager;
56
use OCP\EventDispatcher\IEventDispatcher;
57
use OCP\IConfig;
58
use OCP\IGroupManager;
59
use OCP\IL10N;
60
use OCP\IRequest;
61
use OCP\IUser;
62
use OCP\IUserManager;
63
use OCP\IUserSession;
64
use OCP\L10N\IFactory;
65
use OCP\Mail\IMailer;
66
use function in_array;
67
68
class UsersController extends Controller {
69
	/** @var UserManager */
70
	private $userManager;
71
	/** @var GroupManager */
72
	private $groupManager;
73
	/** @var IUserSession */
74
	private $userSession;
75
	/** @var IConfig */
76
	private $config;
77
	/** @var bool */
78
	private $isAdmin;
79
	/** @var IL10N */
80
	private $l10n;
81
	/** @var IMailer */
82
	private $mailer;
83
	/** @var Factory */
84
	private $l10nFactory;
85
	/** @var IAppManager */
86
	private $appManager;
87
	/** @var AccountManager */
88
	private $accountManager;
89
	/** @var Manager */
90
	private $keyManager;
91
	/** @var IJobList */
92
	private $jobList;
93
	/** @var IManager */
94
	private $encryptionManager;
95
	/** @var IEventDispatcher */
96
	private $dispatcher;
97
98
99
	public function __construct(
100
		string $appName,
101
		IRequest $request,
102
		IUserManager $userManager,
103
		IGroupManager $groupManager,
104
		IUserSession $userSession,
105
		IConfig $config,
106
		bool $isAdmin,
107
		IL10N $l10n,
108
		IMailer $mailer,
109
		IFactory $l10nFactory,
110
		IAppManager $appManager,
111
		AccountManager $accountManager,
112
		Manager $keyManager,
113
		IJobList $jobList,
114
		IManager $encryptionManager,
115
		IEventDispatcher $dispatcher
116
	) {
117
		parent::__construct($appName, $request);
118
		$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...
119
		$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...
120
		$this->userSession = $userSession;
121
		$this->config = $config;
122
		$this->isAdmin = $isAdmin;
123
		$this->l10n = $l10n;
124
		$this->mailer = $mailer;
125
		$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...
126
		$this->appManager = $appManager;
127
		$this->accountManager = $accountManager;
128
		$this->keyManager = $keyManager;
129
		$this->jobList = $jobList;
130
		$this->encryptionManager = $encryptionManager;
131
		$this->dispatcher = $dispatcher;
132
	}
133
134
135
	/**
136
	 * @NoCSRFRequired
137
	 * @NoAdminRequired
138
	 *
139
	 * Display users list template
140
	 *
141
	 * @return TemplateResponse
142
	 */
143
	public function usersListByGroup() {
144
		return $this->usersList();
145
	}
146
147
	/**
148
	 * @NoCSRFRequired
149
	 * @NoAdminRequired
150
	 *
151
	 * Display users list template
152
	 *
153
	 * @return TemplateResponse
154
	 */
155
	public function usersList() {
156
		$user = $this->userSession->getUser();
157
		$uid = $user->getUID();
158
159
		\OC::$server->getNavigationManager()->setActiveEntry('core_users');
160
161
		/* SORT OPTION: SORT_USERCOUNT or SORT_GROUPNAME */
162
		$sortGroupsBy = \OC\Group\MetaData::SORT_USERCOUNT;
163
		$isLDAPUsed = false;
164
		if ($this->config->getSystemValue('sort_groups_by_name', false)) {
165
			$sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME;
166
		} else {
167
			if ($this->appManager->isEnabledForUser('user_ldap')) {
168
				$isLDAPUsed =
169
					$this->groupManager->isBackendUsed('\OCA\User_LDAP\Group_Proxy');
170
				if ($isLDAPUsed) {
171
					// LDAP user count can be slow, so we sort by group name here
172
					$sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME;
173
				}
174
			}
175
		}
176
177
		$canChangePassword = $this->canAdminChangeUserPasswords();
178
179
		/* GROUPS */
180
		$groupsInfo = new \OC\Group\MetaData(
181
			$uid,
182
			$this->isAdmin,
183
			$this->groupManager,
184
			$this->userSession
185
		);
186
187
		$groupsInfo->setSorting($sortGroupsBy);
188
		list($adminGroup, $groups) = $groupsInfo->get();
189
190
		if (!$isLDAPUsed && $this->appManager->isEnabledForUser('user_ldap')) {
191
			$isLDAPUsed = (bool)array_reduce($this->userManager->getBackends(), function ($ldapFound, $backend) {
192
				return $ldapFound || $backend instanceof User_Proxy;
193
			});
194
		}
195
196
		$disabledUsers = -1;
197
		$userCount = 0;
198
199
		if (!$isLDAPUsed) {
200
			if ($this->isAdmin) {
201
				$disabledUsers = $this->userManager->countDisabledUsers();
202
				$userCount = array_reduce($this->userManager->countUsers(), function ($v, $w) {
203
					return $v + (int)$w;
204
				}, 0);
205
			} else {
206
				// User is subadmin !
207
				// Map group list to names to retrieve the countDisabledUsersOfGroups
208
				$userGroups = $this->groupManager->getUserGroups($user);
209
				$groupsNames = [];
210
211
				foreach ($groups as $key => $group) {
212
					// $userCount += (int)$group['usercount'];
213
					array_push($groupsNames, $group['name']);
214
					// we prevent subadmins from looking up themselves
215
					// so we lower the count of the groups he belongs to
216
					if (array_key_exists($group['id'], $userGroups)) {
217
						$groups[$key]['usercount']--;
218
						$userCount -= 1; // we also lower from one the total count
219
					}
220
				}
221
				$userCount += $this->userManager->countUsersOfGroups($groupsInfo->getGroups());
222
				$disabledUsers = $this->userManager->countDisabledUsersOfGroups($groupsNames);
223
			}
224
225
			$userCount -= $disabledUsers;
226
		}
227
228
		$disabledUsersGroup = [
229
			'id' => 'disabled',
230
			'name' => 'Disabled users',
231
			'usercount' => $disabledUsers
232
		];
233
234
		/* QUOTAS PRESETS */
235
		$quotaPreset = $this->parseQuotaPreset($this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB'));
236
		$defaultQuota = $this->config->getAppValue('files', 'default_quota', 'none');
237
238
		$event = new BeforeTemplateRenderedEvent();
239
		$this->dispatcher->dispatch('OC\Settings\Users::loadAdditionalScripts', $event);
240
		$this->dispatcher->dispatchTyped($event);
241
242
		/* LANGUAGES */
243
		$languages = $this->l10nFactory->getLanguages();
244
245
		/* FINAL DATA */
246
		$serverData = [];
247
		// groups
248
		$serverData['groups'] = array_merge_recursive($adminGroup, [$disabledUsersGroup], $groups);
249
		// Various data
250
		$serverData['isAdmin'] = $this->isAdmin;
251
		$serverData['sortGroups'] = $sortGroupsBy;
252
		$serverData['quotaPreset'] = $quotaPreset;
253
		$serverData['userCount'] = $userCount;
254
		$serverData['languages'] = $languages;
255
		$serverData['defaultLanguage'] = $this->config->getSystemValue('default_language', 'en');
256
		$serverData['forceLanguage'] = $this->config->getSystemValue('force_language', false);
257
		// Settings
258
		$serverData['defaultQuota'] = $defaultQuota;
259
		$serverData['canChangePassword'] = $canChangePassword;
260
		$serverData['newUserGenerateUserID'] = $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes';
261
		$serverData['newUserRequireEmail'] = $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes';
262
		$serverData['newUserSendEmail'] = $this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes';
263
264
		return new TemplateResponse('settings', 'settings-vue', ['serverData' => $serverData]);
265
	}
266
267
	/**
268
	 * @param string $key
269
	 * @param string $value
270
	 *
271
	 * @return JSONResponse
272
	 */
273
	public function setPreference(string $key, string $value): JSONResponse {
274
		$allowed = ['newUser.sendEmail'];
275
		if (!in_array($key, $allowed, true)) {
276
			return new JSONResponse([], Http::STATUS_FORBIDDEN);
277
		}
278
279
		$this->config->setAppValue('core', $key, $value);
280
281
		return new JSONResponse([]);
282
	}
283
284
	/**
285
	 * Parse the app value for quota_present
286
	 *
287
	 * @param string $quotaPreset
288
	 * @return array
289
	 */
290
	protected function parseQuotaPreset(string $quotaPreset): array {
291
		// 1 GB, 5 GB, 10 GB => [1 GB, 5 GB, 10 GB]
292
		$presets = array_filter(array_map('trim', explode(',', $quotaPreset)));
293
		// Drop default and none, Make array indexes numerically
294
		return array_values(array_diff($presets, ['default', 'none']));
295
	}
296
297
	/**
298
	 * check if the admin can change the users password
299
	 *
300
	 * The admin can change the passwords if:
301
	 *
302
	 *   - no encryption module is loaded and encryption is disabled
303
	 *   - encryption module is loaded but it doesn't require per user keys
304
	 *
305
	 * The admin can not change the passwords if:
306
	 *
307
	 *   - an encryption module is loaded and it uses per-user keys
308
	 *   - encryption is enabled but no encryption modules are loaded
309
	 *
310
	 * @return bool
311
	 */
312
	protected function canAdminChangeUserPasswords() {
313
		$isEncryptionEnabled = $this->encryptionManager->isEnabled();
314
		try {
315
			$noUserSpecificEncryptionKeys = !$this->encryptionManager->getEncryptionModule()->needDetailedAccessList();
316
			$isEncryptionModuleLoaded = true;
317
		} catch (ModuleDoesNotExistsException $e) {
318
			$noUserSpecificEncryptionKeys = true;
319
			$isEncryptionModuleLoaded = false;
320
		}
321
		$canChangePassword = ($isEncryptionModuleLoaded && $noUserSpecificEncryptionKeys)
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: $canChangePassword = ($i...! $isEncryptionEnabled), Probably Intended Meaning: $canChangePassword = $is...! $isEncryptionEnabled)
Loading history...
322
			|| (!$isEncryptionModuleLoaded && !$isEncryptionEnabled);
323
324
		return $canChangePassword;
325
	}
326
327
	/**
328
	 * @NoAdminRequired
329
	 * @NoSubAdminRequired
330
	 * @PasswordConfirmationRequired
331
	 *
332
	 * @param string $avatarScope
333
	 * @param string $displayname
334
	 * @param string $displaynameScope
335
	 * @param string $phone
336
	 * @param string $phoneScope
337
	 * @param string $email
338
	 * @param string $emailScope
339
	 * @param string $website
340
	 * @param string $websiteScope
341
	 * @param string $address
342
	 * @param string $addressScope
343
	 * @param string $twitter
344
	 * @param string $twitterScope
345
	 * @return DataResponse
346
	 */
347
	public function setUserSettings($avatarScope,
348
									$displayname,
349
									$displaynameScope,
350
									$phone,
351
									$phoneScope,
352
									$email,
353
									$emailScope,
354
									$website,
355
									$websiteScope,
356
									$address,
357
									$addressScope,
358
									$twitter,
359
									$twitterScope
360
	) {
361
		$email = strtolower($email);
362
		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
363
			return new DataResponse(
364
				[
365
					'status' => 'error',
366
					'data' => [
367
						'message' => $this->l10n->t('Invalid mail address')
368
					]
369
				],
370
				Http::STATUS_UNPROCESSABLE_ENTITY
371
			);
372
		}
373
		$user = $this->userSession->getUser();
374
		$data = $this->accountManager->getUser($user);
375
		$data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
376
		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
377
			$data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
378
			$data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
379
		}
380
		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
381
			$shareProvider = \OC::$server->query(FederatedShareProvider::class);
382
			if ($shareProvider->isLookupServerUploadEnabled()) {
0 ignored issues
show
Bug introduced by
The method isLookupServerUploadEnabled() does not exist on stdClass. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

382
			if ($shareProvider->/** @scrutinizer ignore-call */ isLookupServerUploadEnabled()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
383
				$data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
384
				$data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
385
				$data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
386
				$data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
387
			}
388
		}
389
		try {
390
			$this->saveUserSettings($user, $data);
391
			return new DataResponse(
392
				[
393
					'status' => 'success',
394
					'data' => [
395
						'userId' => $user->getUID(),
396
						'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
397
						'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
398
						'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
399
						'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
400
						'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
401
						'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
402
						'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
403
						'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
404
						'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
405
						'message' => $this->l10n->t('Settings saved')
406
					]
407
				],
408
				Http::STATUS_OK
409
			);
410
		} catch (ForbiddenException $e) {
411
			return new DataResponse([
412
				'status' => 'error',
413
				'data' => [
414
					'message' => $e->getMessage()
415
				],
416
			]);
417
		}
418
	}
419
	/**
420
	 * update account manager with new user data
421
	 *
422
	 * @param IUser $user
423
	 * @param array $data
424
	 * @throws ForbiddenException
425
	 */
426
	protected function saveUserSettings(IUser $user, array $data) {
427
		// keep the user back-end up-to-date with the latest display name and email
428
		// address
429
		$oldDisplayName = $user->getDisplayName();
430
		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
0 ignored issues
show
introduced by
The condition is_null($oldDisplayName) is always false.
Loading history...
431
		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
432
			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
433
		) {
434
			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
435
			if ($result === false) {
436
				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
437
			}
438
		}
439
		$oldEmailAddress = $user->getEMailAddress();
440
		$oldEmailAddress = is_null($oldEmailAddress) ? '' : strtolower($oldEmailAddress);
441
		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
442
			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
443
		) {
444
			// this is the only permission a backend provides and is also used
445
			// for the permission of setting a email address
446
			if (!$user->canChangeDisplayName()) {
447
				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
448
			}
449
			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
450
		}
451
		$this->accountManager->updateUser($user, $data);
452
	}
453
454
	/**
455
	 * Set the mail address of a user
456
	 *
457
	 * @NoAdminRequired
458
	 * @NoSubAdminRequired
459
	 * @PasswordConfirmationRequired
460
	 *
461
	 * @param string $account
462
	 * @param bool $onlyVerificationCode only return verification code without updating the data
463
	 * @return DataResponse
464
	 */
465
	public function getVerificationCode(string $account, bool $onlyVerificationCode): DataResponse {
466
		$user = $this->userSession->getUser();
467
468
		if ($user === null) {
469
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
470
		}
471
472
		$accountData = $this->accountManager->getUser($user);
473
		$cloudId = $user->getCloudId();
474
		$message = 'Use my Federated Cloud ID to share with me: ' . $cloudId;
475
		$signature = $this->signMessage($user, $message);
476
477
		$code = $message . ' ' . $signature;
478
		$codeMd5 = $message . ' ' . md5($signature);
479
480
		switch ($account) {
481
			case 'verify-twitter':
482
				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
483
				$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):');
484
				$code = $codeMd5;
485
				$type = AccountManager::PROPERTY_TWITTER;
486
				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
487
				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
488
				break;
489
			case 'verify-website':
490
				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
491
				$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):');
492
				$type = AccountManager::PROPERTY_WEBSITE;
493
				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
494
				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
495
				break;
496
			default:
497
				return new DataResponse([], Http::STATUS_BAD_REQUEST);
498
		}
499
500
		if ($onlyVerificationCode === false) {
501
			$this->accountManager->updateUser($user, $accountData);
502
503
			$this->jobList->add(VerifyUserData::class,
504
				[
505
					'verificationCode' => $code,
506
					'data' => $data,
507
					'type' => $type,
508
					'uid' => $user->getUID(),
509
					'try' => 0,
510
					'lastRun' => $this->getCurrentTime()
511
				]
512
			);
513
		}
514
515
		return new DataResponse(['msg' => $msg, 'code' => $code]);
516
	}
517
518
	/**
519
	 * get current timestamp
520
	 *
521
	 * @return int
522
	 */
523
	protected function getCurrentTime(): int {
524
		return time();
525
	}
526
527
	/**
528
	 * sign message with users private key
529
	 *
530
	 * @param IUser $user
531
	 * @param string $message
532
	 *
533
	 * @return string base64 encoded signature
534
	 */
535
	protected function signMessage(IUser $user, string $message): string {
536
		$privateKey = $this->keyManager->getKey($user)->getPrivate();
537
		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
538
		return base64_encode($signature);
539
	}
540
}
541