Passed
Push — master ( 8f30e6...1bed77 )
by Morris
13:16 queued 10s
created
lib/private/Group/MetaData.php 1 patch
Indentation   +171 added lines, -171 removed lines patch added patch discarded remove patch
@@ -34,175 +34,175 @@
 block discarded – undo
34 34
 use OCP\IUserSession;
35 35
 
36 36
 class MetaData {
37
-	public const SORT_NONE = 0;
38
-	public const SORT_USERCOUNT = 1; // May have performance issues on LDAP backends
39
-	public const SORT_GROUPNAME = 2;
40
-
41
-	/** @var string */
42
-	protected $user;
43
-	/** @var bool */
44
-	protected $isAdmin;
45
-	/** @var array */
46
-	protected $metaData = [];
47
-	/** @var IGroupManager */
48
-	protected $groupManager;
49
-	/** @var bool */
50
-	protected $sorting = false;
51
-	/** @var IUserSession */
52
-	protected $userSession;
53
-
54
-	/**
55
-	 * @param string $user the uid of the current user
56
-	 * @param bool $isAdmin whether the current users is an admin
57
-	 * @param IGroupManager $groupManager
58
-	 * @param IUserSession $userSession
59
-	 */
60
-	public function __construct(
61
-			$user,
62
-			$isAdmin,
63
-			IGroupManager $groupManager,
64
-			IUserSession $userSession
65
-			) {
66
-		$this->user = $user;
67
-		$this->isAdmin = (bool)$isAdmin;
68
-		$this->groupManager = $groupManager;
69
-		$this->userSession = $userSession;
70
-	}
71
-
72
-	/**
73
-	 * returns an array with meta data about all available groups
74
-	 * the array is structured as follows:
75
-	 * [0] array containing meta data about admin groups
76
-	 * [1] array containing meta data about unprivileged groups
77
-	 * @param string $groupSearch only effective when instance was created with
78
-	 * isAdmin being true
79
-	 * @param string $userSearch the pattern users are search for
80
-	 * @return array
81
-	 */
82
-	public function get($groupSearch = '', $userSearch = '') {
83
-		$key = $groupSearch . '::' . $userSearch;
84
-		if (isset($this->metaData[$key])) {
85
-			return $this->metaData[$key];
86
-		}
87
-
88
-		$adminGroups = [];
89
-		$groups = [];
90
-		$sortGroupsIndex = 0;
91
-		$sortGroupsKeys = [];
92
-		$sortAdminGroupsIndex = 0;
93
-		$sortAdminGroupsKeys = [];
94
-
95
-		foreach ($this->getGroups($groupSearch) as $group) {
96
-			$groupMetaData = $this->generateGroupMetaData($group, $userSearch);
97
-			if (strtolower($group->getGID()) !== 'admin') {
98
-				$this->addEntry(
99
-					$groups,
100
-					$sortGroupsKeys,
101
-					$sortGroupsIndex,
102
-					$groupMetaData);
103
-			} else {
104
-				//admin group is hard coded to 'admin' for now. In future,
105
-				//backends may define admin groups too. Then the if statement
106
-				//has to be adjusted accordingly.
107
-				$this->addEntry(
108
-					$adminGroups,
109
-					$sortAdminGroupsKeys,
110
-					$sortAdminGroupsIndex,
111
-					$groupMetaData);
112
-			}
113
-		}
114
-
115
-		//whether sorting is necessary is will be checked in sort()
116
-		$this->sort($groups, $sortGroupsKeys);
117
-		$this->sort($adminGroups, $sortAdminGroupsKeys);
118
-
119
-		$this->metaData[$key] = [$adminGroups, $groups];
120
-		return $this->metaData[$key];
121
-	}
122
-
123
-	/**
124
-	 * sets the sort mode, see SORT_* constants for supported modes
125
-	 *
126
-	 * @param int $sortMode
127
-	 */
128
-	public function setSorting($sortMode) {
129
-		switch ($sortMode) {
130
-			case self::SORT_USERCOUNT:
131
-			case self::SORT_GROUPNAME:
132
-				$this->sorting = $sortMode;
133
-				break;
134
-
135
-			default:
136
-				$this->sorting = self::SORT_NONE;
137
-		}
138
-	}
139
-
140
-	/**
141
-	 * adds an group entry to the resulting array
142
-	 * @param array $entries the resulting array, by reference
143
-	 * @param array $sortKeys the sort key array, by reference
144
-	 * @param int $sortIndex the sort key index, by reference
145
-	 * @param array $data the group's meta data as returned by generateGroupMetaData()
146
-	 */
147
-	private function addEntry(&$entries, &$sortKeys, &$sortIndex, $data) {
148
-		$entries[] = $data;
149
-		if ($this->sorting === self::SORT_USERCOUNT) {
150
-			$sortKeys[$sortIndex] = $data['usercount'];
151
-			$sortIndex++;
152
-		} elseif ($this->sorting === self::SORT_GROUPNAME) {
153
-			$sortKeys[$sortIndex] = $data['name'];
154
-			$sortIndex++;
155
-		}
156
-	}
157
-
158
-	/**
159
-	 * creates an array containing the group meta data
160
-	 * @param \OCP\IGroup $group
161
-	 * @param string $userSearch
162
-	 * @return array with the keys 'id', 'name', 'usercount' and 'disabled'
163
-	 */
164
-	private function generateGroupMetaData(\OCP\IGroup $group, $userSearch) {
165
-		return [
166
-			'id' => $group->getGID(),
167
-			'name' => $group->getDisplayName(),
168
-			'usercount' => $this->sorting === self::SORT_USERCOUNT ? $group->count($userSearch) : 0,
169
-			'disabled' => $group->countDisabled(),
170
-			'canAdd' => $group->canAddUser(),
171
-			'canRemove' => $group->canRemoveUser(),
172
-		];
173
-	}
174
-
175
-	/**
176
-	 * sorts the result array, if applicable
177
-	 * @param array $entries the result array, by reference
178
-	 * @param array $sortKeys the array containing the sort keys
179
-	 * @param return null
180
-	 */
181
-	private function sort(&$entries, $sortKeys) {
182
-		if ($this->sorting === self::SORT_USERCOUNT) {
183
-			array_multisort($sortKeys, SORT_DESC, $entries);
184
-		} elseif ($this->sorting === self::SORT_GROUPNAME) {
185
-			array_multisort($sortKeys, SORT_ASC, $entries);
186
-		}
187
-	}
188
-
189
-	/**
190
-	 * returns the available groups
191
-	 * @param string $search a search string
192
-	 * @return \OCP\IGroup[]
193
-	 */
194
-	public function getGroups($search = '') {
195
-		if ($this->isAdmin) {
196
-			return $this->groupManager->search($search);
197
-		} else {
198
-			$userObject = $this->userSession->getUser();
199
-			if ($userObject !== null) {
200
-				$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($userObject);
201
-			} else {
202
-				$groups = [];
203
-			}
204
-
205
-			return $groups;
206
-		}
207
-	}
37
+    public const SORT_NONE = 0;
38
+    public const SORT_USERCOUNT = 1; // May have performance issues on LDAP backends
39
+    public const SORT_GROUPNAME = 2;
40
+
41
+    /** @var string */
42
+    protected $user;
43
+    /** @var bool */
44
+    protected $isAdmin;
45
+    /** @var array */
46
+    protected $metaData = [];
47
+    /** @var IGroupManager */
48
+    protected $groupManager;
49
+    /** @var bool */
50
+    protected $sorting = false;
51
+    /** @var IUserSession */
52
+    protected $userSession;
53
+
54
+    /**
55
+     * @param string $user the uid of the current user
56
+     * @param bool $isAdmin whether the current users is an admin
57
+     * @param IGroupManager $groupManager
58
+     * @param IUserSession $userSession
59
+     */
60
+    public function __construct(
61
+            $user,
62
+            $isAdmin,
63
+            IGroupManager $groupManager,
64
+            IUserSession $userSession
65
+            ) {
66
+        $this->user = $user;
67
+        $this->isAdmin = (bool)$isAdmin;
68
+        $this->groupManager = $groupManager;
69
+        $this->userSession = $userSession;
70
+    }
71
+
72
+    /**
73
+     * returns an array with meta data about all available groups
74
+     * the array is structured as follows:
75
+     * [0] array containing meta data about admin groups
76
+     * [1] array containing meta data about unprivileged groups
77
+     * @param string $groupSearch only effective when instance was created with
78
+     * isAdmin being true
79
+     * @param string $userSearch the pattern users are search for
80
+     * @return array
81
+     */
82
+    public function get($groupSearch = '', $userSearch = '') {
83
+        $key = $groupSearch . '::' . $userSearch;
84
+        if (isset($this->metaData[$key])) {
85
+            return $this->metaData[$key];
86
+        }
87
+
88
+        $adminGroups = [];
89
+        $groups = [];
90
+        $sortGroupsIndex = 0;
91
+        $sortGroupsKeys = [];
92
+        $sortAdminGroupsIndex = 0;
93
+        $sortAdminGroupsKeys = [];
94
+
95
+        foreach ($this->getGroups($groupSearch) as $group) {
96
+            $groupMetaData = $this->generateGroupMetaData($group, $userSearch);
97
+            if (strtolower($group->getGID()) !== 'admin') {
98
+                $this->addEntry(
99
+                    $groups,
100
+                    $sortGroupsKeys,
101
+                    $sortGroupsIndex,
102
+                    $groupMetaData);
103
+            } else {
104
+                //admin group is hard coded to 'admin' for now. In future,
105
+                //backends may define admin groups too. Then the if statement
106
+                //has to be adjusted accordingly.
107
+                $this->addEntry(
108
+                    $adminGroups,
109
+                    $sortAdminGroupsKeys,
110
+                    $sortAdminGroupsIndex,
111
+                    $groupMetaData);
112
+            }
113
+        }
114
+
115
+        //whether sorting is necessary is will be checked in sort()
116
+        $this->sort($groups, $sortGroupsKeys);
117
+        $this->sort($adminGroups, $sortAdminGroupsKeys);
118
+
119
+        $this->metaData[$key] = [$adminGroups, $groups];
120
+        return $this->metaData[$key];
121
+    }
122
+
123
+    /**
124
+     * sets the sort mode, see SORT_* constants for supported modes
125
+     *
126
+     * @param int $sortMode
127
+     */
128
+    public function setSorting($sortMode) {
129
+        switch ($sortMode) {
130
+            case self::SORT_USERCOUNT:
131
+            case self::SORT_GROUPNAME:
132
+                $this->sorting = $sortMode;
133
+                break;
134
+
135
+            default:
136
+                $this->sorting = self::SORT_NONE;
137
+        }
138
+    }
139
+
140
+    /**
141
+     * adds an group entry to the resulting array
142
+     * @param array $entries the resulting array, by reference
143
+     * @param array $sortKeys the sort key array, by reference
144
+     * @param int $sortIndex the sort key index, by reference
145
+     * @param array $data the group's meta data as returned by generateGroupMetaData()
146
+     */
147
+    private function addEntry(&$entries, &$sortKeys, &$sortIndex, $data) {
148
+        $entries[] = $data;
149
+        if ($this->sorting === self::SORT_USERCOUNT) {
150
+            $sortKeys[$sortIndex] = $data['usercount'];
151
+            $sortIndex++;
152
+        } elseif ($this->sorting === self::SORT_GROUPNAME) {
153
+            $sortKeys[$sortIndex] = $data['name'];
154
+            $sortIndex++;
155
+        }
156
+    }
157
+
158
+    /**
159
+     * creates an array containing the group meta data
160
+     * @param \OCP\IGroup $group
161
+     * @param string $userSearch
162
+     * @return array with the keys 'id', 'name', 'usercount' and 'disabled'
163
+     */
164
+    private function generateGroupMetaData(\OCP\IGroup $group, $userSearch) {
165
+        return [
166
+            'id' => $group->getGID(),
167
+            'name' => $group->getDisplayName(),
168
+            'usercount' => $this->sorting === self::SORT_USERCOUNT ? $group->count($userSearch) : 0,
169
+            'disabled' => $group->countDisabled(),
170
+            'canAdd' => $group->canAddUser(),
171
+            'canRemove' => $group->canRemoveUser(),
172
+        ];
173
+    }
174
+
175
+    /**
176
+     * sorts the result array, if applicable
177
+     * @param array $entries the result array, by reference
178
+     * @param array $sortKeys the array containing the sort keys
179
+     * @param return null
180
+     */
181
+    private function sort(&$entries, $sortKeys) {
182
+        if ($this->sorting === self::SORT_USERCOUNT) {
183
+            array_multisort($sortKeys, SORT_DESC, $entries);
184
+        } elseif ($this->sorting === self::SORT_GROUPNAME) {
185
+            array_multisort($sortKeys, SORT_ASC, $entries);
186
+        }
187
+    }
188
+
189
+    /**
190
+     * returns the available groups
191
+     * @param string $search a search string
192
+     * @return \OCP\IGroup[]
193
+     */
194
+    public function getGroups($search = '') {
195
+        if ($this->isAdmin) {
196
+            return $this->groupManager->search($search);
197
+        } else {
198
+            $userObject = $this->userSession->getUser();
199
+            if ($userObject !== null) {
200
+                $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($userObject);
201
+            } else {
202
+                $groups = [];
203
+            }
204
+
205
+            return $groups;
206
+        }
207
+    }
208 208
 }
Please login to merge, or discard this patch.
apps/settings/lib/Controller/UsersController.php 1 patch
Indentation   +472 added lines, -472 removed lines patch added patch discarded remove patch
@@ -63,476 +63,476 @@
 block discarded – undo
63 63
 use function in_array;
64 64
 
65 65
 class UsersController extends Controller {
66
-	/** @var IUserManager */
67
-	private $userManager;
68
-	/** @var IGroupManager */
69
-	private $groupManager;
70
-	/** @var IUserSession */
71
-	private $userSession;
72
-	/** @var IConfig */
73
-	private $config;
74
-	/** @var bool */
75
-	private $isAdmin;
76
-	/** @var IL10N */
77
-	private $l10n;
78
-	/** @var IMailer */
79
-	private $mailer;
80
-	/** @var IFactory */
81
-	private $l10nFactory;
82
-	/** @var IAppManager */
83
-	private $appManager;
84
-	/** @var AccountManager */
85
-	private $accountManager;
86
-	/** @var Manager */
87
-	private $keyManager;
88
-	/** @var IJobList */
89
-	private $jobList;
90
-	/** @var IManager */
91
-	private $encryptionManager;
92
-	/** @var IEventDispatcher */
93
-	private $dispatcher;
94
-
95
-
96
-	public function __construct(
97
-		string $appName,
98
-		IRequest $request,
99
-		IUserManager $userManager,
100
-		IGroupManager $groupManager,
101
-		IUserSession $userSession,
102
-		IConfig $config,
103
-		bool $isAdmin,
104
-		IL10N $l10n,
105
-		IMailer $mailer,
106
-		IFactory $l10nFactory,
107
-		IAppManager $appManager,
108
-		AccountManager $accountManager,
109
-		Manager $keyManager,
110
-		IJobList $jobList,
111
-		IManager $encryptionManager,
112
-		IEventDispatcher $dispatcher
113
-	) {
114
-		parent::__construct($appName, $request);
115
-		$this->userManager = $userManager;
116
-		$this->groupManager = $groupManager;
117
-		$this->userSession = $userSession;
118
-		$this->config = $config;
119
-		$this->isAdmin = $isAdmin;
120
-		$this->l10n = $l10n;
121
-		$this->mailer = $mailer;
122
-		$this->l10nFactory = $l10nFactory;
123
-		$this->appManager = $appManager;
124
-		$this->accountManager = $accountManager;
125
-		$this->keyManager = $keyManager;
126
-		$this->jobList = $jobList;
127
-		$this->encryptionManager = $encryptionManager;
128
-		$this->dispatcher = $dispatcher;
129
-	}
130
-
131
-
132
-	/**
133
-	 * @NoCSRFRequired
134
-	 * @NoAdminRequired
135
-	 *
136
-	 * Display users list template
137
-	 *
138
-	 * @return TemplateResponse
139
-	 */
140
-	public function usersListByGroup() {
141
-		return $this->usersList();
142
-	}
143
-
144
-	/**
145
-	 * @NoCSRFRequired
146
-	 * @NoAdminRequired
147
-	 *
148
-	 * Display users list template
149
-	 *
150
-	 * @return TemplateResponse
151
-	 */
152
-	public function usersList() {
153
-		$user = $this->userSession->getUser();
154
-		$uid = $user->getUID();
155
-
156
-		\OC::$server->getNavigationManager()->setActiveEntry('core_users');
157
-
158
-		/* SORT OPTION: SORT_USERCOUNT or SORT_GROUPNAME */
159
-		$sortGroupsBy = \OC\Group\MetaData::SORT_USERCOUNT;
160
-		$isLDAPUsed = false;
161
-		if ($this->config->getSystemValue('sort_groups_by_name', false)) {
162
-			$sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME;
163
-		} else {
164
-			if ($this->appManager->isEnabledForUser('user_ldap')) {
165
-				$isLDAPUsed =
166
-					$this->groupManager->isBackendUsed('\OCA\User_LDAP\Group_Proxy');
167
-				if ($isLDAPUsed) {
168
-					// LDAP user count can be slow, so we sort by group name here
169
-					$sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME;
170
-				}
171
-			}
172
-		}
173
-
174
-		$canChangePassword = $this->canAdminChangeUserPasswords();
175
-
176
-		/* GROUPS */
177
-		$groupsInfo = new \OC\Group\MetaData(
178
-			$uid,
179
-			$this->isAdmin,
180
-			$this->groupManager,
181
-			$this->userSession
182
-		);
183
-
184
-		$groupsInfo->setSorting($sortGroupsBy);
185
-		list($adminGroup, $groups) = $groupsInfo->get();
186
-
187
-		if (!$isLDAPUsed && $this->appManager->isEnabledForUser('user_ldap')) {
188
-			$isLDAPUsed = (bool)array_reduce($this->userManager->getBackends(), function ($ldapFound, $backend) {
189
-				return $ldapFound || $backend instanceof User_Proxy;
190
-			});
191
-		}
192
-
193
-		$disabledUsers = -1;
194
-		$userCount = 0;
195
-
196
-		if (!$isLDAPUsed) {
197
-			if ($this->isAdmin) {
198
-				$disabledUsers = $this->userManager->countDisabledUsers();
199
-				$userCount = array_reduce($this->userManager->countUsers(), function ($v, $w) {
200
-					return $v + (int)$w;
201
-				}, 0);
202
-			} else {
203
-				// User is subadmin !
204
-				// Map group list to names to retrieve the countDisabledUsersOfGroups
205
-				$userGroups = $this->groupManager->getUserGroups($user);
206
-				$groupsNames = [];
207
-
208
-				foreach ($groups as $key => $group) {
209
-					// $userCount += (int)$group['usercount'];
210
-					array_push($groupsNames, $group['name']);
211
-					// we prevent subadmins from looking up themselves
212
-					// so we lower the count of the groups he belongs to
213
-					if (array_key_exists($group['id'], $userGroups)) {
214
-						$groups[$key]['usercount']--;
215
-						$userCount -= 1; // we also lower from one the total count
216
-					}
217
-				}
218
-				$userCount += $this->userManager->countUsersOfGroups($groupsInfo->getGroups());
219
-				$disabledUsers = $this->userManager->countDisabledUsersOfGroups($groupsNames);
220
-			}
221
-
222
-			$userCount -= $disabledUsers;
223
-		}
224
-
225
-		$disabledUsersGroup = [
226
-			'id' => 'disabled',
227
-			'name' => 'Disabled users',
228
-			'usercount' => $disabledUsers
229
-		];
230
-
231
-		/* QUOTAS PRESETS */
232
-		$quotaPreset = $this->parseQuotaPreset($this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB'));
233
-		$defaultQuota = $this->config->getAppValue('files', 'default_quota', 'none');
234
-
235
-		$event = new BeforeTemplateRenderedEvent();
236
-		$this->dispatcher->dispatch('OC\Settings\Users::loadAdditionalScripts', $event);
237
-		$this->dispatcher->dispatchTyped($event);
238
-
239
-		/* LANGUAGES */
240
-		$languages = $this->l10nFactory->getLanguages();
241
-
242
-		/* FINAL DATA */
243
-		$serverData = [];
244
-		// groups
245
-		$serverData['groups'] = array_merge_recursive($adminGroup, [$disabledUsersGroup], $groups);
246
-		// Various data
247
-		$serverData['isAdmin'] = $this->isAdmin;
248
-		$serverData['sortGroups'] = $sortGroupsBy;
249
-		$serverData['quotaPreset'] = $quotaPreset;
250
-		$serverData['userCount'] = $userCount;
251
-		$serverData['languages'] = $languages;
252
-		$serverData['defaultLanguage'] = $this->config->getSystemValue('default_language', 'en');
253
-		$serverData['forceLanguage'] = $this->config->getSystemValue('force_language', false);
254
-		// Settings
255
-		$serverData['defaultQuota'] = $defaultQuota;
256
-		$serverData['canChangePassword'] = $canChangePassword;
257
-		$serverData['newUserGenerateUserID'] = $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes';
258
-		$serverData['newUserRequireEmail'] = $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes';
259
-		$serverData['newUserSendEmail'] = $this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes';
260
-
261
-		return new TemplateResponse('settings', 'settings-vue', ['serverData' => $serverData]);
262
-	}
263
-
264
-	/**
265
-	 * @param string $key
266
-	 * @param string $value
267
-	 *
268
-	 * @return JSONResponse
269
-	 */
270
-	public function setPreference(string $key, string $value): JSONResponse {
271
-		$allowed = ['newUser.sendEmail'];
272
-		if (!in_array($key, $allowed, true)) {
273
-			return new JSONResponse([], Http::STATUS_FORBIDDEN);
274
-		}
275
-
276
-		$this->config->setAppValue('core', $key, $value);
277
-
278
-		return new JSONResponse([]);
279
-	}
280
-
281
-	/**
282
-	 * Parse the app value for quota_present
283
-	 *
284
-	 * @param string $quotaPreset
285
-	 * @return array
286
-	 */
287
-	protected function parseQuotaPreset(string $quotaPreset): array {
288
-		// 1 GB, 5 GB, 10 GB => [1 GB, 5 GB, 10 GB]
289
-		$presets = array_filter(array_map('trim', explode(',', $quotaPreset)));
290
-		// Drop default and none, Make array indexes numerically
291
-		return array_values(array_diff($presets, ['default', 'none']));
292
-	}
293
-
294
-	/**
295
-	 * check if the admin can change the users password
296
-	 *
297
-	 * The admin can change the passwords if:
298
-	 *
299
-	 *   - no encryption module is loaded and encryption is disabled
300
-	 *   - encryption module is loaded but it doesn't require per user keys
301
-	 *
302
-	 * The admin can not change the passwords if:
303
-	 *
304
-	 *   - an encryption module is loaded and it uses per-user keys
305
-	 *   - encryption is enabled but no encryption modules are loaded
306
-	 *
307
-	 * @return bool
308
-	 */
309
-	protected function canAdminChangeUserPasswords() {
310
-		$isEncryptionEnabled = $this->encryptionManager->isEnabled();
311
-		try {
312
-			$noUserSpecificEncryptionKeys =!$this->encryptionManager->getEncryptionModule()->needDetailedAccessList();
313
-			$isEncryptionModuleLoaded = true;
314
-		} catch (ModuleDoesNotExistsException $e) {
315
-			$noUserSpecificEncryptionKeys = true;
316
-			$isEncryptionModuleLoaded = false;
317
-		}
318
-
319
-		$canChangePassword = ($isEncryptionEnabled && $isEncryptionModuleLoaded  && $noUserSpecificEncryptionKeys)
320
-			|| (!$isEncryptionEnabled && !$isEncryptionModuleLoaded)
321
-			|| (!$isEncryptionEnabled && $isEncryptionModuleLoaded && $noUserSpecificEncryptionKeys);
322
-
323
-		return $canChangePassword;
324
-	}
325
-
326
-	/**
327
-	 * @NoAdminRequired
328
-	 * @NoSubAdminRequired
329
-	 * @PasswordConfirmationRequired
330
-	 *
331
-	 * @param string $avatarScope
332
-	 * @param string $displayname
333
-	 * @param string $displaynameScope
334
-	 * @param string $phone
335
-	 * @param string $phoneScope
336
-	 * @param string $email
337
-	 * @param string $emailScope
338
-	 * @param string $website
339
-	 * @param string $websiteScope
340
-	 * @param string $address
341
-	 * @param string $addressScope
342
-	 * @param string $twitter
343
-	 * @param string $twitterScope
344
-	 * @return DataResponse
345
-	 */
346
-	public function setUserSettings($avatarScope,
347
-									$displayname,
348
-									$displaynameScope,
349
-									$phone,
350
-									$phoneScope,
351
-									$email,
352
-									$emailScope,
353
-									$website,
354
-									$websiteScope,
355
-									$address,
356
-									$addressScope,
357
-									$twitter,
358
-									$twitterScope
359
-	) {
360
-		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
361
-			return new DataResponse(
362
-				[
363
-					'status' => 'error',
364
-					'data' => [
365
-						'message' => $this->l10n->t('Invalid mail address')
366
-					]
367
-				],
368
-				Http::STATUS_UNPROCESSABLE_ENTITY
369
-			);
370
-		}
371
-		$user = $this->userSession->getUser();
372
-		$data = $this->accountManager->getUser($user);
373
-		$data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
374
-		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
375
-			$data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
376
-			$data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
377
-		}
378
-		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
379
-			$shareProvider = \OC::$server->query(FederatedShareProvider::class);
380
-			if ($shareProvider->isLookupServerUploadEnabled()) {
381
-				$data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
382
-				$data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
383
-				$data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
384
-				$data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
385
-			}
386
-		}
387
-		try {
388
-			$this->saveUserSettings($user, $data);
389
-			return new DataResponse(
390
-				[
391
-					'status' => 'success',
392
-					'data' => [
393
-						'userId' => $user->getUID(),
394
-						'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
395
-						'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
396
-						'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
397
-						'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
398
-						'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
399
-						'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
400
-						'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
401
-						'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
402
-						'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
403
-						'message' => $this->l10n->t('Settings saved')
404
-					]
405
-				],
406
-				Http::STATUS_OK
407
-			);
408
-		} catch (ForbiddenException $e) {
409
-			return new DataResponse([
410
-				'status' => 'error',
411
-				'data' => [
412
-					'message' => $e->getMessage()
413
-				],
414
-			]);
415
-		}
416
-	}
417
-	/**
418
-	 * update account manager with new user data
419
-	 *
420
-	 * @param IUser $user
421
-	 * @param array $data
422
-	 * @throws ForbiddenException
423
-	 */
424
-	protected function saveUserSettings(IUser $user, array $data) {
425
-		// keep the user back-end up-to-date with the latest display name and email
426
-		// address
427
-		$oldDisplayName = $user->getDisplayName();
428
-		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
429
-		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
430
-			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
431
-		) {
432
-			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
433
-			if ($result === false) {
434
-				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
435
-			}
436
-		}
437
-		$oldEmailAddress = $user->getEMailAddress();
438
-		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
439
-		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
440
-			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
441
-		) {
442
-			// this is the only permission a backend provides and is also used
443
-			// for the permission of setting a email address
444
-			if (!$user->canChangeDisplayName()) {
445
-				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
446
-			}
447
-			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
448
-		}
449
-		$this->accountManager->updateUser($user, $data);
450
-	}
451
-
452
-	/**
453
-	 * Set the mail address of a user
454
-	 *
455
-	 * @NoAdminRequired
456
-	 * @NoSubAdminRequired
457
-	 * @PasswordConfirmationRequired
458
-	 *
459
-	 * @param string $account
460
-	 * @param bool $onlyVerificationCode only return verification code without updating the data
461
-	 * @return DataResponse
462
-	 */
463
-	public function getVerificationCode(string $account, bool $onlyVerificationCode): DataResponse {
464
-		$user = $this->userSession->getUser();
465
-
466
-		if ($user === null) {
467
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
468
-		}
469
-
470
-		$accountData = $this->accountManager->getUser($user);
471
-		$cloudId = $user->getCloudId();
472
-		$message = 'Use my Federated Cloud ID to share with me: ' . $cloudId;
473
-		$signature = $this->signMessage($user, $message);
474
-
475
-		$code = $message . ' ' . $signature;
476
-		$codeMd5 = $message . ' ' . md5($signature);
477
-
478
-		switch ($account) {
479
-			case 'verify-twitter':
480
-				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
481
-				$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):');
482
-				$code = $codeMd5;
483
-				$type = AccountManager::PROPERTY_TWITTER;
484
-				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
485
-				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
486
-				break;
487
-			case 'verify-website':
488
-				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
489
-				$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):');
490
-				$type = AccountManager::PROPERTY_WEBSITE;
491
-				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
492
-				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
493
-				break;
494
-			default:
495
-				return new DataResponse([], Http::STATUS_BAD_REQUEST);
496
-		}
497
-
498
-		if ($onlyVerificationCode === false) {
499
-			$this->accountManager->updateUser($user, $accountData);
500
-
501
-			$this->jobList->add(VerifyUserData::class,
502
-				[
503
-					'verificationCode' => $code,
504
-					'data' => $data,
505
-					'type' => $type,
506
-					'uid' => $user->getUID(),
507
-					'try' => 0,
508
-					'lastRun' => $this->getCurrentTime()
509
-				]
510
-			);
511
-		}
512
-
513
-		return new DataResponse(['msg' => $msg, 'code' => $code]);
514
-	}
515
-
516
-	/**
517
-	 * get current timestamp
518
-	 *
519
-	 * @return int
520
-	 */
521
-	protected function getCurrentTime(): int {
522
-		return time();
523
-	}
524
-
525
-	/**
526
-	 * sign message with users private key
527
-	 *
528
-	 * @param IUser $user
529
-	 * @param string $message
530
-	 *
531
-	 * @return string base64 encoded signature
532
-	 */
533
-	protected function signMessage(IUser $user, string $message): string {
534
-		$privateKey = $this->keyManager->getKey($user)->getPrivate();
535
-		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
536
-		return base64_encode($signature);
537
-	}
66
+    /** @var IUserManager */
67
+    private $userManager;
68
+    /** @var IGroupManager */
69
+    private $groupManager;
70
+    /** @var IUserSession */
71
+    private $userSession;
72
+    /** @var IConfig */
73
+    private $config;
74
+    /** @var bool */
75
+    private $isAdmin;
76
+    /** @var IL10N */
77
+    private $l10n;
78
+    /** @var IMailer */
79
+    private $mailer;
80
+    /** @var IFactory */
81
+    private $l10nFactory;
82
+    /** @var IAppManager */
83
+    private $appManager;
84
+    /** @var AccountManager */
85
+    private $accountManager;
86
+    /** @var Manager */
87
+    private $keyManager;
88
+    /** @var IJobList */
89
+    private $jobList;
90
+    /** @var IManager */
91
+    private $encryptionManager;
92
+    /** @var IEventDispatcher */
93
+    private $dispatcher;
94
+
95
+
96
+    public function __construct(
97
+        string $appName,
98
+        IRequest $request,
99
+        IUserManager $userManager,
100
+        IGroupManager $groupManager,
101
+        IUserSession $userSession,
102
+        IConfig $config,
103
+        bool $isAdmin,
104
+        IL10N $l10n,
105
+        IMailer $mailer,
106
+        IFactory $l10nFactory,
107
+        IAppManager $appManager,
108
+        AccountManager $accountManager,
109
+        Manager $keyManager,
110
+        IJobList $jobList,
111
+        IManager $encryptionManager,
112
+        IEventDispatcher $dispatcher
113
+    ) {
114
+        parent::__construct($appName, $request);
115
+        $this->userManager = $userManager;
116
+        $this->groupManager = $groupManager;
117
+        $this->userSession = $userSession;
118
+        $this->config = $config;
119
+        $this->isAdmin = $isAdmin;
120
+        $this->l10n = $l10n;
121
+        $this->mailer = $mailer;
122
+        $this->l10nFactory = $l10nFactory;
123
+        $this->appManager = $appManager;
124
+        $this->accountManager = $accountManager;
125
+        $this->keyManager = $keyManager;
126
+        $this->jobList = $jobList;
127
+        $this->encryptionManager = $encryptionManager;
128
+        $this->dispatcher = $dispatcher;
129
+    }
130
+
131
+
132
+    /**
133
+     * @NoCSRFRequired
134
+     * @NoAdminRequired
135
+     *
136
+     * Display users list template
137
+     *
138
+     * @return TemplateResponse
139
+     */
140
+    public function usersListByGroup() {
141
+        return $this->usersList();
142
+    }
143
+
144
+    /**
145
+     * @NoCSRFRequired
146
+     * @NoAdminRequired
147
+     *
148
+     * Display users list template
149
+     *
150
+     * @return TemplateResponse
151
+     */
152
+    public function usersList() {
153
+        $user = $this->userSession->getUser();
154
+        $uid = $user->getUID();
155
+
156
+        \OC::$server->getNavigationManager()->setActiveEntry('core_users');
157
+
158
+        /* SORT OPTION: SORT_USERCOUNT or SORT_GROUPNAME */
159
+        $sortGroupsBy = \OC\Group\MetaData::SORT_USERCOUNT;
160
+        $isLDAPUsed = false;
161
+        if ($this->config->getSystemValue('sort_groups_by_name', false)) {
162
+            $sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME;
163
+        } else {
164
+            if ($this->appManager->isEnabledForUser('user_ldap')) {
165
+                $isLDAPUsed =
166
+                    $this->groupManager->isBackendUsed('\OCA\User_LDAP\Group_Proxy');
167
+                if ($isLDAPUsed) {
168
+                    // LDAP user count can be slow, so we sort by group name here
169
+                    $sortGroupsBy = \OC\Group\MetaData::SORT_GROUPNAME;
170
+                }
171
+            }
172
+        }
173
+
174
+        $canChangePassword = $this->canAdminChangeUserPasswords();
175
+
176
+        /* GROUPS */
177
+        $groupsInfo = new \OC\Group\MetaData(
178
+            $uid,
179
+            $this->isAdmin,
180
+            $this->groupManager,
181
+            $this->userSession
182
+        );
183
+
184
+        $groupsInfo->setSorting($sortGroupsBy);
185
+        list($adminGroup, $groups) = $groupsInfo->get();
186
+
187
+        if (!$isLDAPUsed && $this->appManager->isEnabledForUser('user_ldap')) {
188
+            $isLDAPUsed = (bool)array_reduce($this->userManager->getBackends(), function ($ldapFound, $backend) {
189
+                return $ldapFound || $backend instanceof User_Proxy;
190
+            });
191
+        }
192
+
193
+        $disabledUsers = -1;
194
+        $userCount = 0;
195
+
196
+        if (!$isLDAPUsed) {
197
+            if ($this->isAdmin) {
198
+                $disabledUsers = $this->userManager->countDisabledUsers();
199
+                $userCount = array_reduce($this->userManager->countUsers(), function ($v, $w) {
200
+                    return $v + (int)$w;
201
+                }, 0);
202
+            } else {
203
+                // User is subadmin !
204
+                // Map group list to names to retrieve the countDisabledUsersOfGroups
205
+                $userGroups = $this->groupManager->getUserGroups($user);
206
+                $groupsNames = [];
207
+
208
+                foreach ($groups as $key => $group) {
209
+                    // $userCount += (int)$group['usercount'];
210
+                    array_push($groupsNames, $group['name']);
211
+                    // we prevent subadmins from looking up themselves
212
+                    // so we lower the count of the groups he belongs to
213
+                    if (array_key_exists($group['id'], $userGroups)) {
214
+                        $groups[$key]['usercount']--;
215
+                        $userCount -= 1; // we also lower from one the total count
216
+                    }
217
+                }
218
+                $userCount += $this->userManager->countUsersOfGroups($groupsInfo->getGroups());
219
+                $disabledUsers = $this->userManager->countDisabledUsersOfGroups($groupsNames);
220
+            }
221
+
222
+            $userCount -= $disabledUsers;
223
+        }
224
+
225
+        $disabledUsersGroup = [
226
+            'id' => 'disabled',
227
+            'name' => 'Disabled users',
228
+            'usercount' => $disabledUsers
229
+        ];
230
+
231
+        /* QUOTAS PRESETS */
232
+        $quotaPreset = $this->parseQuotaPreset($this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB'));
233
+        $defaultQuota = $this->config->getAppValue('files', 'default_quota', 'none');
234
+
235
+        $event = new BeforeTemplateRenderedEvent();
236
+        $this->dispatcher->dispatch('OC\Settings\Users::loadAdditionalScripts', $event);
237
+        $this->dispatcher->dispatchTyped($event);
238
+
239
+        /* LANGUAGES */
240
+        $languages = $this->l10nFactory->getLanguages();
241
+
242
+        /* FINAL DATA */
243
+        $serverData = [];
244
+        // groups
245
+        $serverData['groups'] = array_merge_recursive($adminGroup, [$disabledUsersGroup], $groups);
246
+        // Various data
247
+        $serverData['isAdmin'] = $this->isAdmin;
248
+        $serverData['sortGroups'] = $sortGroupsBy;
249
+        $serverData['quotaPreset'] = $quotaPreset;
250
+        $serverData['userCount'] = $userCount;
251
+        $serverData['languages'] = $languages;
252
+        $serverData['defaultLanguage'] = $this->config->getSystemValue('default_language', 'en');
253
+        $serverData['forceLanguage'] = $this->config->getSystemValue('force_language', false);
254
+        // Settings
255
+        $serverData['defaultQuota'] = $defaultQuota;
256
+        $serverData['canChangePassword'] = $canChangePassword;
257
+        $serverData['newUserGenerateUserID'] = $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes';
258
+        $serverData['newUserRequireEmail'] = $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes';
259
+        $serverData['newUserSendEmail'] = $this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes';
260
+
261
+        return new TemplateResponse('settings', 'settings-vue', ['serverData' => $serverData]);
262
+    }
263
+
264
+    /**
265
+     * @param string $key
266
+     * @param string $value
267
+     *
268
+     * @return JSONResponse
269
+     */
270
+    public function setPreference(string $key, string $value): JSONResponse {
271
+        $allowed = ['newUser.sendEmail'];
272
+        if (!in_array($key, $allowed, true)) {
273
+            return new JSONResponse([], Http::STATUS_FORBIDDEN);
274
+        }
275
+
276
+        $this->config->setAppValue('core', $key, $value);
277
+
278
+        return new JSONResponse([]);
279
+    }
280
+
281
+    /**
282
+     * Parse the app value for quota_present
283
+     *
284
+     * @param string $quotaPreset
285
+     * @return array
286
+     */
287
+    protected function parseQuotaPreset(string $quotaPreset): array {
288
+        // 1 GB, 5 GB, 10 GB => [1 GB, 5 GB, 10 GB]
289
+        $presets = array_filter(array_map('trim', explode(',', $quotaPreset)));
290
+        // Drop default and none, Make array indexes numerically
291
+        return array_values(array_diff($presets, ['default', 'none']));
292
+    }
293
+
294
+    /**
295
+     * check if the admin can change the users password
296
+     *
297
+     * The admin can change the passwords if:
298
+     *
299
+     *   - no encryption module is loaded and encryption is disabled
300
+     *   - encryption module is loaded but it doesn't require per user keys
301
+     *
302
+     * The admin can not change the passwords if:
303
+     *
304
+     *   - an encryption module is loaded and it uses per-user keys
305
+     *   - encryption is enabled but no encryption modules are loaded
306
+     *
307
+     * @return bool
308
+     */
309
+    protected function canAdminChangeUserPasswords() {
310
+        $isEncryptionEnabled = $this->encryptionManager->isEnabled();
311
+        try {
312
+            $noUserSpecificEncryptionKeys =!$this->encryptionManager->getEncryptionModule()->needDetailedAccessList();
313
+            $isEncryptionModuleLoaded = true;
314
+        } catch (ModuleDoesNotExistsException $e) {
315
+            $noUserSpecificEncryptionKeys = true;
316
+            $isEncryptionModuleLoaded = false;
317
+        }
318
+
319
+        $canChangePassword = ($isEncryptionEnabled && $isEncryptionModuleLoaded  && $noUserSpecificEncryptionKeys)
320
+            || (!$isEncryptionEnabled && !$isEncryptionModuleLoaded)
321
+            || (!$isEncryptionEnabled && $isEncryptionModuleLoaded && $noUserSpecificEncryptionKeys);
322
+
323
+        return $canChangePassword;
324
+    }
325
+
326
+    /**
327
+     * @NoAdminRequired
328
+     * @NoSubAdminRequired
329
+     * @PasswordConfirmationRequired
330
+     *
331
+     * @param string $avatarScope
332
+     * @param string $displayname
333
+     * @param string $displaynameScope
334
+     * @param string $phone
335
+     * @param string $phoneScope
336
+     * @param string $email
337
+     * @param string $emailScope
338
+     * @param string $website
339
+     * @param string $websiteScope
340
+     * @param string $address
341
+     * @param string $addressScope
342
+     * @param string $twitter
343
+     * @param string $twitterScope
344
+     * @return DataResponse
345
+     */
346
+    public function setUserSettings($avatarScope,
347
+                                    $displayname,
348
+                                    $displaynameScope,
349
+                                    $phone,
350
+                                    $phoneScope,
351
+                                    $email,
352
+                                    $emailScope,
353
+                                    $website,
354
+                                    $websiteScope,
355
+                                    $address,
356
+                                    $addressScope,
357
+                                    $twitter,
358
+                                    $twitterScope
359
+    ) {
360
+        if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
361
+            return new DataResponse(
362
+                [
363
+                    'status' => 'error',
364
+                    'data' => [
365
+                        'message' => $this->l10n->t('Invalid mail address')
366
+                    ]
367
+                ],
368
+                Http::STATUS_UNPROCESSABLE_ENTITY
369
+            );
370
+        }
371
+        $user = $this->userSession->getUser();
372
+        $data = $this->accountManager->getUser($user);
373
+        $data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
374
+        if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
375
+            $data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
376
+            $data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
377
+        }
378
+        if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
379
+            $shareProvider = \OC::$server->query(FederatedShareProvider::class);
380
+            if ($shareProvider->isLookupServerUploadEnabled()) {
381
+                $data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
382
+                $data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
383
+                $data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
384
+                $data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
385
+            }
386
+        }
387
+        try {
388
+            $this->saveUserSettings($user, $data);
389
+            return new DataResponse(
390
+                [
391
+                    'status' => 'success',
392
+                    'data' => [
393
+                        'userId' => $user->getUID(),
394
+                        'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
395
+                        'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
396
+                        'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
397
+                        'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
398
+                        'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
399
+                        'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
400
+                        'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
401
+                        'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
402
+                        'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
403
+                        'message' => $this->l10n->t('Settings saved')
404
+                    ]
405
+                ],
406
+                Http::STATUS_OK
407
+            );
408
+        } catch (ForbiddenException $e) {
409
+            return new DataResponse([
410
+                'status' => 'error',
411
+                'data' => [
412
+                    'message' => $e->getMessage()
413
+                ],
414
+            ]);
415
+        }
416
+    }
417
+    /**
418
+     * update account manager with new user data
419
+     *
420
+     * @param IUser $user
421
+     * @param array $data
422
+     * @throws ForbiddenException
423
+     */
424
+    protected function saveUserSettings(IUser $user, array $data) {
425
+        // keep the user back-end up-to-date with the latest display name and email
426
+        // address
427
+        $oldDisplayName = $user->getDisplayName();
428
+        $oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
429
+        if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
430
+            && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
431
+        ) {
432
+            $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
433
+            if ($result === false) {
434
+                throw new ForbiddenException($this->l10n->t('Unable to change full name'));
435
+            }
436
+        }
437
+        $oldEmailAddress = $user->getEMailAddress();
438
+        $oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
439
+        if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
440
+            && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
441
+        ) {
442
+            // this is the only permission a backend provides and is also used
443
+            // for the permission of setting a email address
444
+            if (!$user->canChangeDisplayName()) {
445
+                throw new ForbiddenException($this->l10n->t('Unable to change email address'));
446
+            }
447
+            $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
448
+        }
449
+        $this->accountManager->updateUser($user, $data);
450
+    }
451
+
452
+    /**
453
+     * Set the mail address of a user
454
+     *
455
+     * @NoAdminRequired
456
+     * @NoSubAdminRequired
457
+     * @PasswordConfirmationRequired
458
+     *
459
+     * @param string $account
460
+     * @param bool $onlyVerificationCode only return verification code without updating the data
461
+     * @return DataResponse
462
+     */
463
+    public function getVerificationCode(string $account, bool $onlyVerificationCode): DataResponse {
464
+        $user = $this->userSession->getUser();
465
+
466
+        if ($user === null) {
467
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
468
+        }
469
+
470
+        $accountData = $this->accountManager->getUser($user);
471
+        $cloudId = $user->getCloudId();
472
+        $message = 'Use my Federated Cloud ID to share with me: ' . $cloudId;
473
+        $signature = $this->signMessage($user, $message);
474
+
475
+        $code = $message . ' ' . $signature;
476
+        $codeMd5 = $message . ' ' . md5($signature);
477
+
478
+        switch ($account) {
479
+            case 'verify-twitter':
480
+                $accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
481
+                $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):');
482
+                $code = $codeMd5;
483
+                $type = AccountManager::PROPERTY_TWITTER;
484
+                $data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
485
+                $accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
486
+                break;
487
+            case 'verify-website':
488
+                $accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
489
+                $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):');
490
+                $type = AccountManager::PROPERTY_WEBSITE;
491
+                $data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
492
+                $accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
493
+                break;
494
+            default:
495
+                return new DataResponse([], Http::STATUS_BAD_REQUEST);
496
+        }
497
+
498
+        if ($onlyVerificationCode === false) {
499
+            $this->accountManager->updateUser($user, $accountData);
500
+
501
+            $this->jobList->add(VerifyUserData::class,
502
+                [
503
+                    'verificationCode' => $code,
504
+                    'data' => $data,
505
+                    'type' => $type,
506
+                    'uid' => $user->getUID(),
507
+                    'try' => 0,
508
+                    'lastRun' => $this->getCurrentTime()
509
+                ]
510
+            );
511
+        }
512
+
513
+        return new DataResponse(['msg' => $msg, 'code' => $code]);
514
+    }
515
+
516
+    /**
517
+     * get current timestamp
518
+     *
519
+     * @return int
520
+     */
521
+    protected function getCurrentTime(): int {
522
+        return time();
523
+    }
524
+
525
+    /**
526
+     * sign message with users private key
527
+     *
528
+     * @param IUser $user
529
+     * @param string $message
530
+     *
531
+     * @return string base64 encoded signature
532
+     */
533
+    protected function signMessage(IUser $user, string $message): string {
534
+        $privateKey = $this->keyManager->getKey($user)->getPrivate();
535
+        openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
536
+        return base64_encode($signature);
537
+    }
538 538
 }
Please login to merge, or discard this patch.