Passed
Push — master ( a30d7c...c7c113 )
by Julius
33:01 queued 16:15
created
lib/private/User/Database.php 2 patches
Indentation   +467 added lines, -467 removed lines patch added patch discarded remove patch
@@ -65,471 +65,471 @@
 block discarded – undo
65 65
  * Class for user management in a SQL Database (e.g. MySQL, SQLite)
66 66
  */
67 67
 class Database extends ABackend implements
68
-	ICreateUserBackend,
69
-	ISetPasswordBackend,
70
-	ISetDisplayNameBackend,
71
-	IGetDisplayNameBackend,
72
-	ICheckPasswordBackend,
73
-	IGetHomeBackend,
74
-	ICountUsersBackend,
75
-	ISearchKnownUsersBackend,
76
-	IGetRealUIDBackend {
77
-	/** @var CappedMemoryCache */
78
-	private $cache;
79
-
80
-	/** @var IEventDispatcher */
81
-	private $eventDispatcher;
82
-
83
-	/** @var IDBConnection */
84
-	private $dbConn;
85
-
86
-	/** @var string */
87
-	private $table;
88
-
89
-	use TTransactional;
90
-
91
-	/**
92
-	 * \OC\User\Database constructor.
93
-	 *
94
-	 * @param IEventDispatcher $eventDispatcher
95
-	 * @param string $table
96
-	 */
97
-	public function __construct($eventDispatcher = null, $table = 'users') {
98
-		$this->cache = new CappedMemoryCache();
99
-		$this->table = $table;
100
-		$this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->query(IEventDispatcher::class);
101
-	}
102
-
103
-	/**
104
-	 * FIXME: This function should not be required!
105
-	 */
106
-	private function fixDI() {
107
-		if ($this->dbConn === null) {
108
-			$this->dbConn = \OC::$server->getDatabaseConnection();
109
-		}
110
-	}
111
-
112
-	/**
113
-	 * Create a new user
114
-	 *
115
-	 * @param string $uid The username of the user to create
116
-	 * @param string $password The password of the new user
117
-	 * @return bool
118
-	 *
119
-	 * Creates a new user. Basic checking of username is done in OC_User
120
-	 * itself, not in its subclasses.
121
-	 */
122
-	public function createUser(string $uid, string $password): bool {
123
-		$this->fixDI();
124
-
125
-		if (!$this->userExists($uid)) {
126
-			$this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
127
-
128
-			return $this->atomic(function () use ($uid, $password) {
129
-				$qb = $this->dbConn->getQueryBuilder();
130
-				$qb->insert($this->table)
131
-					->values([
132
-						'uid' => $qb->createNamedParameter($uid),
133
-						'password' => $qb->createNamedParameter(\OC::$server->getHasher()->hash($password)),
134
-						'uid_lower' => $qb->createNamedParameter(mb_strtolower($uid)),
135
-					]);
136
-
137
-				$result = $qb->executeStatement();
138
-
139
-				// Clear cache
140
-				unset($this->cache[$uid]);
141
-				// Repopulate the cache
142
-				$this->loadUser($uid);
143
-
144
-				return (bool) $result;
145
-			}, $this->dbConn);
146
-		}
147
-
148
-		return false;
149
-	}
150
-
151
-	/**
152
-	 * delete a user
153
-	 *
154
-	 * @param string $uid The username of the user to delete
155
-	 * @return bool
156
-	 *
157
-	 * Deletes a user
158
-	 */
159
-	public function deleteUser($uid) {
160
-		$this->fixDI();
161
-
162
-		// Delete user-group-relation
163
-		$query = $this->dbConn->getQueryBuilder();
164
-		$query->delete($this->table)
165
-			->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
166
-		$result = $query->execute();
167
-
168
-		if (isset($this->cache[$uid])) {
169
-			unset($this->cache[$uid]);
170
-		}
171
-
172
-		return $result ? true : false;
173
-	}
174
-
175
-	private function updatePassword(string $uid, string $passwordHash): bool {
176
-		$query = $this->dbConn->getQueryBuilder();
177
-		$query->update($this->table)
178
-			->set('password', $query->createNamedParameter($passwordHash))
179
-			->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
180
-		$result = $query->execute();
181
-
182
-		return $result ? true : false;
183
-	}
184
-
185
-	/**
186
-	 * Set password
187
-	 *
188
-	 * @param string $uid The username
189
-	 * @param string $password The new password
190
-	 * @return bool
191
-	 *
192
-	 * Change the password of a user
193
-	 */
194
-	public function setPassword(string $uid, string $password): bool {
195
-		$this->fixDI();
196
-
197
-		if ($this->userExists($uid)) {
198
-			$this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
199
-
200
-			$hasher = \OC::$server->getHasher();
201
-			$hashedPassword = $hasher->hash($password);
202
-
203
-			$return = $this->updatePassword($uid, $hashedPassword);
204
-
205
-			if ($return) {
206
-				$this->cache[$uid]['password'] = $hashedPassword;
207
-			}
208
-
209
-			return $return;
210
-		}
211
-
212
-		return false;
213
-	}
214
-
215
-	/**
216
-	 * Set display name
217
-	 *
218
-	 * @param string $uid The username
219
-	 * @param string $displayName The new display name
220
-	 * @return bool
221
-	 *
222
-	 * @throws \InvalidArgumentException
223
-	 *
224
-	 * Change the display name of a user
225
-	 */
226
-	public function setDisplayName(string $uid, string $displayName): bool {
227
-		if (mb_strlen($displayName) > 64) {
228
-			throw new \InvalidArgumentException('Invalid displayname');
229
-		}
230
-
231
-		$this->fixDI();
232
-
233
-		if ($this->userExists($uid)) {
234
-			$query = $this->dbConn->getQueryBuilder();
235
-			$query->update($this->table)
236
-				->set('displayname', $query->createNamedParameter($displayName))
237
-				->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
238
-			$query->execute();
239
-
240
-			$this->cache[$uid]['displayname'] = $displayName;
241
-
242
-			return true;
243
-		}
244
-
245
-		return false;
246
-	}
247
-
248
-	/**
249
-	 * get display name of the user
250
-	 *
251
-	 * @param string $uid user ID of the user
252
-	 * @return string display name
253
-	 */
254
-	public function getDisplayName($uid): string {
255
-		$uid = (string)$uid;
256
-		$this->loadUser($uid);
257
-		return empty($this->cache[$uid]['displayname']) ? $uid : $this->cache[$uid]['displayname'];
258
-	}
259
-
260
-	/**
261
-	 * Get a list of all display names and user ids.
262
-	 *
263
-	 * @param string $search
264
-	 * @param int|null $limit
265
-	 * @param int|null $offset
266
-	 * @return array an array of all displayNames (value) and the corresponding uids (key)
267
-	 */
268
-	public function getDisplayNames($search = '', $limit = null, $offset = null) {
269
-		$limit = $this->fixLimit($limit);
270
-
271
-		$this->fixDI();
272
-
273
-		$query = $this->dbConn->getQueryBuilder();
274
-
275
-		$query->select('uid', 'displayname')
276
-			->from($this->table, 'u')
277
-			->leftJoin('u', 'preferences', 'p', $query->expr()->andX(
278
-				$query->expr()->eq('userid', 'uid'),
279
-				$query->expr()->eq('appid', $query->expr()->literal('settings')),
280
-				$query->expr()->eq('configkey', $query->expr()->literal('email')))
281
-			)
282
-			// sqlite doesn't like re-using a single named parameter here
283
-			->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
284
-			->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
285
-			->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
286
-			->orderBy($query->func()->lower('displayname'), 'ASC')
287
-			->addOrderBy('uid_lower', 'ASC')
288
-			->setMaxResults($limit)
289
-			->setFirstResult($offset);
290
-
291
-		$result = $query->executeQuery();
292
-		$displayNames = [];
293
-		while ($row = $result->fetch()) {
294
-			$displayNames[(string)$row['uid']] = (string)$row['displayname'];
295
-		}
296
-
297
-		return $displayNames;
298
-	}
299
-
300
-	/**
301
-	 * @param string $searcher
302
-	 * @param string $pattern
303
-	 * @param int|null $limit
304
-	 * @param int|null $offset
305
-	 * @return array
306
-	 * @since 21.0.1
307
-	 */
308
-	public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array {
309
-		$limit = $this->fixLimit($limit);
310
-
311
-		$this->fixDI();
312
-
313
-		$query = $this->dbConn->getQueryBuilder();
314
-
315
-		$query->select('u.uid', 'u.displayname')
316
-			->from($this->table, 'u')
317
-			->leftJoin('u', 'known_users', 'k', $query->expr()->andX(
318
-				$query->expr()->eq('k.known_user', 'u.uid'),
319
-				$query->expr()->eq('k.known_to', $query->createNamedParameter($searcher))
320
-			))
321
-			->where($query->expr()->eq('k.known_to', $query->createNamedParameter($searcher)))
322
-			->andWhere($query->expr()->orX(
323
-				$query->expr()->iLike('u.uid', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%')),
324
-				$query->expr()->iLike('u.displayname', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%'))
325
-			))
326
-			->orderBy('u.displayname', 'ASC')
327
-			->addOrderBy('u.uid_lower', 'ASC')
328
-			->setMaxResults($limit)
329
-			->setFirstResult($offset);
330
-
331
-		$result = $query->execute();
332
-		$displayNames = [];
333
-		while ($row = $result->fetch()) {
334
-			$displayNames[(string)$row['uid']] = (string)$row['displayname'];
335
-		}
336
-
337
-		return $displayNames;
338
-	}
339
-
340
-	/**
341
-	 * Check if the password is correct
342
-	 *
343
-	 * @param string $loginName The loginname
344
-	 * @param string $password The password
345
-	 * @return string
346
-	 *
347
-	 * Check if the password is correct without logging in the user
348
-	 * returns the user id or false
349
-	 */
350
-	public function checkPassword(string $loginName, string $password) {
351
-		$found = $this->loadUser($loginName);
352
-
353
-		if ($found && is_array($this->cache[$loginName])) {
354
-			$storedHash = $this->cache[$loginName]['password'];
355
-			$newHash = '';
356
-			if (\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) {
357
-				if (!empty($newHash)) {
358
-					$this->updatePassword($loginName, $newHash);
359
-				}
360
-				return (string)$this->cache[$loginName]['uid'];
361
-			}
362
-		}
363
-
364
-		return false;
365
-	}
366
-
367
-	/**
368
-	 * Load an user in the cache
369
-	 *
370
-	 * @param string $uid the username
371
-	 * @return boolean true if user was found, false otherwise
372
-	 */
373
-	private function loadUser($uid) {
374
-		$this->fixDI();
375
-
376
-		$uid = (string)$uid;
377
-		if (!isset($this->cache[$uid])) {
378
-			//guests $uid could be NULL or ''
379
-			if ($uid === '') {
380
-				$this->cache[$uid] = false;
381
-				return true;
382
-			}
383
-
384
-			$qb = $this->dbConn->getQueryBuilder();
385
-			$qb->select('uid', 'displayname', 'password')
386
-				->from($this->table)
387
-				->where(
388
-					$qb->expr()->eq(
389
-						'uid_lower', $qb->createNamedParameter(mb_strtolower($uid))
390
-					)
391
-				);
392
-			$result = $qb->execute();
393
-			$row = $result->fetch();
394
-			$result->closeCursor();
395
-
396
-			// "uid" is primary key, so there can only be a single result
397
-			if ($row !== false) {
398
-				$this->cache[$uid] = [
399
-					'uid' => (string)$row['uid'],
400
-					'displayname' => (string)$row['displayname'],
401
-					'password' => (string)$row['password'],
402
-				];
403
-			} else {
404
-				$this->cache[$uid] = false;
405
-				return false;
406
-			}
407
-		}
408
-
409
-		return true;
410
-	}
411
-
412
-	/**
413
-	 * Get a list of all users
414
-	 *
415
-	 * @param string $search
416
-	 * @param null|int $limit
417
-	 * @param null|int $offset
418
-	 * @return string[] an array of all uids
419
-	 */
420
-	public function getUsers($search = '', $limit = null, $offset = null) {
421
-		$limit = $this->fixLimit($limit);
422
-
423
-		$users = $this->getDisplayNames($search, $limit, $offset);
424
-		$userIds = array_map(function ($uid) {
425
-			return (string)$uid;
426
-		}, array_keys($users));
427
-		sort($userIds, SORT_STRING | SORT_FLAG_CASE);
428
-		return $userIds;
429
-	}
430
-
431
-	/**
432
-	 * check if a user exists
433
-	 *
434
-	 * @param string $uid the username
435
-	 * @return boolean
436
-	 */
437
-	public function userExists($uid) {
438
-		$this->loadUser($uid);
439
-		return $this->cache[$uid] !== false;
440
-	}
441
-
442
-	/**
443
-	 * get the user's home directory
444
-	 *
445
-	 * @param string $uid the username
446
-	 * @return string|false
447
-	 */
448
-	public function getHome(string $uid) {
449
-		if ($this->userExists($uid)) {
450
-			return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid;
451
-		}
452
-
453
-		return false;
454
-	}
455
-
456
-	/**
457
-	 * @return bool
458
-	 */
459
-	public function hasUserListings() {
460
-		return true;
461
-	}
462
-
463
-	/**
464
-	 * counts the users in the database
465
-	 *
466
-	 * @return int|false
467
-	 */
468
-	public function countUsers() {
469
-		$this->fixDI();
470
-
471
-		$query = $this->dbConn->getQueryBuilder();
472
-		$query->select($query->func()->count('uid'))
473
-			->from($this->table);
474
-		$result = $query->executeQuery();
475
-
476
-		return $result->fetchOne();
477
-	}
478
-
479
-	/**
480
-	 * returns the username for the given login name in the correct casing
481
-	 *
482
-	 * @param string $loginName
483
-	 * @return string|false
484
-	 */
485
-	public function loginName2UserName($loginName) {
486
-		if ($this->userExists($loginName)) {
487
-			return $this->cache[$loginName]['uid'];
488
-		}
489
-
490
-		return false;
491
-	}
492
-
493
-	/**
494
-	 * Backend name to be shown in user management
495
-	 *
496
-	 * @return string the name of the backend to be shown
497
-	 */
498
-	public function getBackendName() {
499
-		return 'Database';
500
-	}
501
-
502
-	public static function preLoginNameUsedAsUserName($param) {
503
-		if (!isset($param['uid'])) {
504
-			throw new \Exception('key uid is expected to be set in $param');
505
-		}
506
-
507
-		$backends = \OC::$server->getUserManager()->getBackends();
508
-		foreach ($backends as $backend) {
509
-			if ($backend instanceof Database) {
510
-				/** @var \OC\User\Database $backend */
511
-				$uid = $backend->loginName2UserName($param['uid']);
512
-				if ($uid !== false) {
513
-					$param['uid'] = $uid;
514
-					return;
515
-				}
516
-			}
517
-		}
518
-	}
519
-
520
-	public function getRealUID(string $uid): string {
521
-		if (!$this->userExists($uid)) {
522
-			throw new \RuntimeException($uid . ' does not exist');
523
-		}
524
-
525
-		return $this->cache[$uid]['uid'];
526
-	}
527
-
528
-	private function fixLimit($limit) {
529
-		if (is_int($limit) && $limit >= 0) {
530
-			return $limit;
531
-		}
532
-
533
-		return null;
534
-	}
68
+    ICreateUserBackend,
69
+    ISetPasswordBackend,
70
+    ISetDisplayNameBackend,
71
+    IGetDisplayNameBackend,
72
+    ICheckPasswordBackend,
73
+    IGetHomeBackend,
74
+    ICountUsersBackend,
75
+    ISearchKnownUsersBackend,
76
+    IGetRealUIDBackend {
77
+    /** @var CappedMemoryCache */
78
+    private $cache;
79
+
80
+    /** @var IEventDispatcher */
81
+    private $eventDispatcher;
82
+
83
+    /** @var IDBConnection */
84
+    private $dbConn;
85
+
86
+    /** @var string */
87
+    private $table;
88
+
89
+    use TTransactional;
90
+
91
+    /**
92
+     * \OC\User\Database constructor.
93
+     *
94
+     * @param IEventDispatcher $eventDispatcher
95
+     * @param string $table
96
+     */
97
+    public function __construct($eventDispatcher = null, $table = 'users') {
98
+        $this->cache = new CappedMemoryCache();
99
+        $this->table = $table;
100
+        $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->query(IEventDispatcher::class);
101
+    }
102
+
103
+    /**
104
+     * FIXME: This function should not be required!
105
+     */
106
+    private function fixDI() {
107
+        if ($this->dbConn === null) {
108
+            $this->dbConn = \OC::$server->getDatabaseConnection();
109
+        }
110
+    }
111
+
112
+    /**
113
+     * Create a new user
114
+     *
115
+     * @param string $uid The username of the user to create
116
+     * @param string $password The password of the new user
117
+     * @return bool
118
+     *
119
+     * Creates a new user. Basic checking of username is done in OC_User
120
+     * itself, not in its subclasses.
121
+     */
122
+    public function createUser(string $uid, string $password): bool {
123
+        $this->fixDI();
124
+
125
+        if (!$this->userExists($uid)) {
126
+            $this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
127
+
128
+            return $this->atomic(function () use ($uid, $password) {
129
+                $qb = $this->dbConn->getQueryBuilder();
130
+                $qb->insert($this->table)
131
+                    ->values([
132
+                        'uid' => $qb->createNamedParameter($uid),
133
+                        'password' => $qb->createNamedParameter(\OC::$server->getHasher()->hash($password)),
134
+                        'uid_lower' => $qb->createNamedParameter(mb_strtolower($uid)),
135
+                    ]);
136
+
137
+                $result = $qb->executeStatement();
138
+
139
+                // Clear cache
140
+                unset($this->cache[$uid]);
141
+                // Repopulate the cache
142
+                $this->loadUser($uid);
143
+
144
+                return (bool) $result;
145
+            }, $this->dbConn);
146
+        }
147
+
148
+        return false;
149
+    }
150
+
151
+    /**
152
+     * delete a user
153
+     *
154
+     * @param string $uid The username of the user to delete
155
+     * @return bool
156
+     *
157
+     * Deletes a user
158
+     */
159
+    public function deleteUser($uid) {
160
+        $this->fixDI();
161
+
162
+        // Delete user-group-relation
163
+        $query = $this->dbConn->getQueryBuilder();
164
+        $query->delete($this->table)
165
+            ->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
166
+        $result = $query->execute();
167
+
168
+        if (isset($this->cache[$uid])) {
169
+            unset($this->cache[$uid]);
170
+        }
171
+
172
+        return $result ? true : false;
173
+    }
174
+
175
+    private function updatePassword(string $uid, string $passwordHash): bool {
176
+        $query = $this->dbConn->getQueryBuilder();
177
+        $query->update($this->table)
178
+            ->set('password', $query->createNamedParameter($passwordHash))
179
+            ->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
180
+        $result = $query->execute();
181
+
182
+        return $result ? true : false;
183
+    }
184
+
185
+    /**
186
+     * Set password
187
+     *
188
+     * @param string $uid The username
189
+     * @param string $password The new password
190
+     * @return bool
191
+     *
192
+     * Change the password of a user
193
+     */
194
+    public function setPassword(string $uid, string $password): bool {
195
+        $this->fixDI();
196
+
197
+        if ($this->userExists($uid)) {
198
+            $this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
199
+
200
+            $hasher = \OC::$server->getHasher();
201
+            $hashedPassword = $hasher->hash($password);
202
+
203
+            $return = $this->updatePassword($uid, $hashedPassword);
204
+
205
+            if ($return) {
206
+                $this->cache[$uid]['password'] = $hashedPassword;
207
+            }
208
+
209
+            return $return;
210
+        }
211
+
212
+        return false;
213
+    }
214
+
215
+    /**
216
+     * Set display name
217
+     *
218
+     * @param string $uid The username
219
+     * @param string $displayName The new display name
220
+     * @return bool
221
+     *
222
+     * @throws \InvalidArgumentException
223
+     *
224
+     * Change the display name of a user
225
+     */
226
+    public function setDisplayName(string $uid, string $displayName): bool {
227
+        if (mb_strlen($displayName) > 64) {
228
+            throw new \InvalidArgumentException('Invalid displayname');
229
+        }
230
+
231
+        $this->fixDI();
232
+
233
+        if ($this->userExists($uid)) {
234
+            $query = $this->dbConn->getQueryBuilder();
235
+            $query->update($this->table)
236
+                ->set('displayname', $query->createNamedParameter($displayName))
237
+                ->where($query->expr()->eq('uid_lower', $query->createNamedParameter(mb_strtolower($uid))));
238
+            $query->execute();
239
+
240
+            $this->cache[$uid]['displayname'] = $displayName;
241
+
242
+            return true;
243
+        }
244
+
245
+        return false;
246
+    }
247
+
248
+    /**
249
+     * get display name of the user
250
+     *
251
+     * @param string $uid user ID of the user
252
+     * @return string display name
253
+     */
254
+    public function getDisplayName($uid): string {
255
+        $uid = (string)$uid;
256
+        $this->loadUser($uid);
257
+        return empty($this->cache[$uid]['displayname']) ? $uid : $this->cache[$uid]['displayname'];
258
+    }
259
+
260
+    /**
261
+     * Get a list of all display names and user ids.
262
+     *
263
+     * @param string $search
264
+     * @param int|null $limit
265
+     * @param int|null $offset
266
+     * @return array an array of all displayNames (value) and the corresponding uids (key)
267
+     */
268
+    public function getDisplayNames($search = '', $limit = null, $offset = null) {
269
+        $limit = $this->fixLimit($limit);
270
+
271
+        $this->fixDI();
272
+
273
+        $query = $this->dbConn->getQueryBuilder();
274
+
275
+        $query->select('uid', 'displayname')
276
+            ->from($this->table, 'u')
277
+            ->leftJoin('u', 'preferences', 'p', $query->expr()->andX(
278
+                $query->expr()->eq('userid', 'uid'),
279
+                $query->expr()->eq('appid', $query->expr()->literal('settings')),
280
+                $query->expr()->eq('configkey', $query->expr()->literal('email')))
281
+            )
282
+            // sqlite doesn't like re-using a single named parameter here
283
+            ->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
284
+            ->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
285
+            ->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
286
+            ->orderBy($query->func()->lower('displayname'), 'ASC')
287
+            ->addOrderBy('uid_lower', 'ASC')
288
+            ->setMaxResults($limit)
289
+            ->setFirstResult($offset);
290
+
291
+        $result = $query->executeQuery();
292
+        $displayNames = [];
293
+        while ($row = $result->fetch()) {
294
+            $displayNames[(string)$row['uid']] = (string)$row['displayname'];
295
+        }
296
+
297
+        return $displayNames;
298
+    }
299
+
300
+    /**
301
+     * @param string $searcher
302
+     * @param string $pattern
303
+     * @param int|null $limit
304
+     * @param int|null $offset
305
+     * @return array
306
+     * @since 21.0.1
307
+     */
308
+    public function searchKnownUsersByDisplayName(string $searcher, string $pattern, ?int $limit = null, ?int $offset = null): array {
309
+        $limit = $this->fixLimit($limit);
310
+
311
+        $this->fixDI();
312
+
313
+        $query = $this->dbConn->getQueryBuilder();
314
+
315
+        $query->select('u.uid', 'u.displayname')
316
+            ->from($this->table, 'u')
317
+            ->leftJoin('u', 'known_users', 'k', $query->expr()->andX(
318
+                $query->expr()->eq('k.known_user', 'u.uid'),
319
+                $query->expr()->eq('k.known_to', $query->createNamedParameter($searcher))
320
+            ))
321
+            ->where($query->expr()->eq('k.known_to', $query->createNamedParameter($searcher)))
322
+            ->andWhere($query->expr()->orX(
323
+                $query->expr()->iLike('u.uid', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%')),
324
+                $query->expr()->iLike('u.displayname', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%'))
325
+            ))
326
+            ->orderBy('u.displayname', 'ASC')
327
+            ->addOrderBy('u.uid_lower', 'ASC')
328
+            ->setMaxResults($limit)
329
+            ->setFirstResult($offset);
330
+
331
+        $result = $query->execute();
332
+        $displayNames = [];
333
+        while ($row = $result->fetch()) {
334
+            $displayNames[(string)$row['uid']] = (string)$row['displayname'];
335
+        }
336
+
337
+        return $displayNames;
338
+    }
339
+
340
+    /**
341
+     * Check if the password is correct
342
+     *
343
+     * @param string $loginName The loginname
344
+     * @param string $password The password
345
+     * @return string
346
+     *
347
+     * Check if the password is correct without logging in the user
348
+     * returns the user id or false
349
+     */
350
+    public function checkPassword(string $loginName, string $password) {
351
+        $found = $this->loadUser($loginName);
352
+
353
+        if ($found && is_array($this->cache[$loginName])) {
354
+            $storedHash = $this->cache[$loginName]['password'];
355
+            $newHash = '';
356
+            if (\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) {
357
+                if (!empty($newHash)) {
358
+                    $this->updatePassword($loginName, $newHash);
359
+                }
360
+                return (string)$this->cache[$loginName]['uid'];
361
+            }
362
+        }
363
+
364
+        return false;
365
+    }
366
+
367
+    /**
368
+     * Load an user in the cache
369
+     *
370
+     * @param string $uid the username
371
+     * @return boolean true if user was found, false otherwise
372
+     */
373
+    private function loadUser($uid) {
374
+        $this->fixDI();
375
+
376
+        $uid = (string)$uid;
377
+        if (!isset($this->cache[$uid])) {
378
+            //guests $uid could be NULL or ''
379
+            if ($uid === '') {
380
+                $this->cache[$uid] = false;
381
+                return true;
382
+            }
383
+
384
+            $qb = $this->dbConn->getQueryBuilder();
385
+            $qb->select('uid', 'displayname', 'password')
386
+                ->from($this->table)
387
+                ->where(
388
+                    $qb->expr()->eq(
389
+                        'uid_lower', $qb->createNamedParameter(mb_strtolower($uid))
390
+                    )
391
+                );
392
+            $result = $qb->execute();
393
+            $row = $result->fetch();
394
+            $result->closeCursor();
395
+
396
+            // "uid" is primary key, so there can only be a single result
397
+            if ($row !== false) {
398
+                $this->cache[$uid] = [
399
+                    'uid' => (string)$row['uid'],
400
+                    'displayname' => (string)$row['displayname'],
401
+                    'password' => (string)$row['password'],
402
+                ];
403
+            } else {
404
+                $this->cache[$uid] = false;
405
+                return false;
406
+            }
407
+        }
408
+
409
+        return true;
410
+    }
411
+
412
+    /**
413
+     * Get a list of all users
414
+     *
415
+     * @param string $search
416
+     * @param null|int $limit
417
+     * @param null|int $offset
418
+     * @return string[] an array of all uids
419
+     */
420
+    public function getUsers($search = '', $limit = null, $offset = null) {
421
+        $limit = $this->fixLimit($limit);
422
+
423
+        $users = $this->getDisplayNames($search, $limit, $offset);
424
+        $userIds = array_map(function ($uid) {
425
+            return (string)$uid;
426
+        }, array_keys($users));
427
+        sort($userIds, SORT_STRING | SORT_FLAG_CASE);
428
+        return $userIds;
429
+    }
430
+
431
+    /**
432
+     * check if a user exists
433
+     *
434
+     * @param string $uid the username
435
+     * @return boolean
436
+     */
437
+    public function userExists($uid) {
438
+        $this->loadUser($uid);
439
+        return $this->cache[$uid] !== false;
440
+    }
441
+
442
+    /**
443
+     * get the user's home directory
444
+     *
445
+     * @param string $uid the username
446
+     * @return string|false
447
+     */
448
+    public function getHome(string $uid) {
449
+        if ($this->userExists($uid)) {
450
+            return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid;
451
+        }
452
+
453
+        return false;
454
+    }
455
+
456
+    /**
457
+     * @return bool
458
+     */
459
+    public function hasUserListings() {
460
+        return true;
461
+    }
462
+
463
+    /**
464
+     * counts the users in the database
465
+     *
466
+     * @return int|false
467
+     */
468
+    public function countUsers() {
469
+        $this->fixDI();
470
+
471
+        $query = $this->dbConn->getQueryBuilder();
472
+        $query->select($query->func()->count('uid'))
473
+            ->from($this->table);
474
+        $result = $query->executeQuery();
475
+
476
+        return $result->fetchOne();
477
+    }
478
+
479
+    /**
480
+     * returns the username for the given login name in the correct casing
481
+     *
482
+     * @param string $loginName
483
+     * @return string|false
484
+     */
485
+    public function loginName2UserName($loginName) {
486
+        if ($this->userExists($loginName)) {
487
+            return $this->cache[$loginName]['uid'];
488
+        }
489
+
490
+        return false;
491
+    }
492
+
493
+    /**
494
+     * Backend name to be shown in user management
495
+     *
496
+     * @return string the name of the backend to be shown
497
+     */
498
+    public function getBackendName() {
499
+        return 'Database';
500
+    }
501
+
502
+    public static function preLoginNameUsedAsUserName($param) {
503
+        if (!isset($param['uid'])) {
504
+            throw new \Exception('key uid is expected to be set in $param');
505
+        }
506
+
507
+        $backends = \OC::$server->getUserManager()->getBackends();
508
+        foreach ($backends as $backend) {
509
+            if ($backend instanceof Database) {
510
+                /** @var \OC\User\Database $backend */
511
+                $uid = $backend->loginName2UserName($param['uid']);
512
+                if ($uid !== false) {
513
+                    $param['uid'] = $uid;
514
+                    return;
515
+                }
516
+            }
517
+        }
518
+    }
519
+
520
+    public function getRealUID(string $uid): string {
521
+        if (!$this->userExists($uid)) {
522
+            throw new \RuntimeException($uid . ' does not exist');
523
+        }
524
+
525
+        return $this->cache[$uid]['uid'];
526
+    }
527
+
528
+    private function fixLimit($limit) {
529
+        if (is_int($limit) && $limit >= 0) {
530
+            return $limit;
531
+        }
532
+
533
+        return null;
534
+    }
535 535
 }
Please login to merge, or discard this patch.
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
 		if (!$this->userExists($uid)) {
126 126
 			$this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
127 127
 
128
-			return $this->atomic(function () use ($uid, $password) {
128
+			return $this->atomic(function() use ($uid, $password) {
129 129
 				$qb = $this->dbConn->getQueryBuilder();
130 130
 				$qb->insert($this->table)
131 131
 					->values([
@@ -252,7 +252,7 @@  discard block
 block discarded – undo
252 252
 	 * @return string display name
253 253
 	 */
254 254
 	public function getDisplayName($uid): string {
255
-		$uid = (string)$uid;
255
+		$uid = (string) $uid;
256 256
 		$this->loadUser($uid);
257 257
 		return empty($this->cache[$uid]['displayname']) ? $uid : $this->cache[$uid]['displayname'];
258 258
 	}
@@ -280,9 +280,9 @@  discard block
 block discarded – undo
280 280
 				$query->expr()->eq('configkey', $query->expr()->literal('email')))
281 281
 			)
282 282
 			// sqlite doesn't like re-using a single named parameter here
283
-			->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
284
-			->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
285
-			->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
283
+			->where($query->expr()->iLike('uid', $query->createPositionalParameter('%'.$this->dbConn->escapeLikeParameter($search).'%')))
284
+			->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%'.$this->dbConn->escapeLikeParameter($search).'%')))
285
+			->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%'.$this->dbConn->escapeLikeParameter($search).'%')))
286 286
 			->orderBy($query->func()->lower('displayname'), 'ASC')
287 287
 			->addOrderBy('uid_lower', 'ASC')
288 288
 			->setMaxResults($limit)
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
 		$result = $query->executeQuery();
292 292
 		$displayNames = [];
293 293
 		while ($row = $result->fetch()) {
294
-			$displayNames[(string)$row['uid']] = (string)$row['displayname'];
294
+			$displayNames[(string) $row['uid']] = (string) $row['displayname'];
295 295
 		}
296 296
 
297 297
 		return $displayNames;
@@ -320,8 +320,8 @@  discard block
 block discarded – undo
320 320
 			))
321 321
 			->where($query->expr()->eq('k.known_to', $query->createNamedParameter($searcher)))
322 322
 			->andWhere($query->expr()->orX(
323
-				$query->expr()->iLike('u.uid', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%')),
324
-				$query->expr()->iLike('u.displayname', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($pattern) . '%'))
323
+				$query->expr()->iLike('u.uid', $query->createNamedParameter('%'.$this->dbConn->escapeLikeParameter($pattern).'%')),
324
+				$query->expr()->iLike('u.displayname', $query->createNamedParameter('%'.$this->dbConn->escapeLikeParameter($pattern).'%'))
325 325
 			))
326 326
 			->orderBy('u.displayname', 'ASC')
327 327
 			->addOrderBy('u.uid_lower', 'ASC')
@@ -331,7 +331,7 @@  discard block
 block discarded – undo
331 331
 		$result = $query->execute();
332 332
 		$displayNames = [];
333 333
 		while ($row = $result->fetch()) {
334
-			$displayNames[(string)$row['uid']] = (string)$row['displayname'];
334
+			$displayNames[(string) $row['uid']] = (string) $row['displayname'];
335 335
 		}
336 336
 
337 337
 		return $displayNames;
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
 				if (!empty($newHash)) {
358 358
 					$this->updatePassword($loginName, $newHash);
359 359
 				}
360
-				return (string)$this->cache[$loginName]['uid'];
360
+				return (string) $this->cache[$loginName]['uid'];
361 361
 			}
362 362
 		}
363 363
 
@@ -373,7 +373,7 @@  discard block
 block discarded – undo
373 373
 	private function loadUser($uid) {
374 374
 		$this->fixDI();
375 375
 
376
-		$uid = (string)$uid;
376
+		$uid = (string) $uid;
377 377
 		if (!isset($this->cache[$uid])) {
378 378
 			//guests $uid could be NULL or ''
379 379
 			if ($uid === '') {
@@ -396,9 +396,9 @@  discard block
 block discarded – undo
396 396
 			// "uid" is primary key, so there can only be a single result
397 397
 			if ($row !== false) {
398 398
 				$this->cache[$uid] = [
399
-					'uid' => (string)$row['uid'],
400
-					'displayname' => (string)$row['displayname'],
401
-					'password' => (string)$row['password'],
399
+					'uid' => (string) $row['uid'],
400
+					'displayname' => (string) $row['displayname'],
401
+					'password' => (string) $row['password'],
402 402
 				];
403 403
 			} else {
404 404
 				$this->cache[$uid] = false;
@@ -421,8 +421,8 @@  discard block
 block discarded – undo
421 421
 		$limit = $this->fixLimit($limit);
422 422
 
423 423
 		$users = $this->getDisplayNames($search, $limit, $offset);
424
-		$userIds = array_map(function ($uid) {
425
-			return (string)$uid;
424
+		$userIds = array_map(function($uid) {
425
+			return (string) $uid;
426 426
 		}, array_keys($users));
427 427
 		sort($userIds, SORT_STRING | SORT_FLAG_CASE);
428 428
 		return $userIds;
@@ -447,7 +447,7 @@  discard block
 block discarded – undo
447 447
 	 */
448 448
 	public function getHome(string $uid) {
449 449
 		if ($this->userExists($uid)) {
450
-			return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid;
450
+			return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/'.$uid;
451 451
 		}
452 452
 
453 453
 		return false;
@@ -519,7 +519,7 @@  discard block
 block discarded – undo
519 519
 
520 520
 	public function getRealUID(string $uid): string {
521 521
 		if (!$this->userExists($uid)) {
522
-			throw new \RuntimeException($uid . ' does not exist');
522
+			throw new \RuntimeException($uid.' does not exist');
523 523
 		}
524 524
 
525 525
 		return $this->cache[$uid]['uid'];
Please login to merge, or discard this patch.