Added support for case sensitive usernames

This commit is contained in:
Matias Griese
2020-06-02 11:57:55 +03:00
parent 93942a74cf
commit f12bd1b51f
10 changed files with 121 additions and 15 deletions

View File

@@ -2,7 +2,7 @@ title: Flex User Accounts
description: Manage your User Accounts in Flex.
type: flex-objects
# Deprecated in Grav 1.7.0-rc.4: file was renamed.
# Deprecated in Grav 1.7.0-rc.4: file was renamed to user-accounts.yaml
extends@:
type: user-accounts
context: blueprints://flex

View File

@@ -113,6 +113,7 @@ config:
pattern: '{FOLDER}/{KEY}{EXT}'
indexed: true
key: username
case_sensitive: false
search:
options:
contains: 1

View File

@@ -15,6 +15,21 @@ use Grav\Framework\Flex\Storage\FileStorage;
class UserFileStorage extends FileStorage
{
public $caseSensitive;
/**
* @param string $key
* @return string
*/
public function normalizeKey(string $key): string
{
if ($this->caseSensitive === true) {
return $key;
}
return mb_strtolower($key);
}
/**
* {@inheritdoc}
* @see FlexStorageInterface::getMediaPath()
@@ -40,4 +55,15 @@ class UserFileStorage extends FileStorage
$row['access'] = $access;
}
}
/**
* @param array $options
* @return void
*/
protected function initOptions(array $options): void
{
parent::initOptions($options);
$this->caseSensitive = $options['case_sensitive'] ?? false;
}
}

View File

@@ -15,6 +15,21 @@ use Grav\Framework\Flex\Storage\FolderStorage;
class UserFolderStorage extends FolderStorage
{
public $caseSensitive;
/**
* @param string $key
* @return string
*/
public function normalizeKey(string $key): string
{
if ($this->caseSensitive === true) {
return $key;
}
return mb_strtolower($key);
}
/**
* Prepares the row for saving and returns the storage key for the record.
*
@@ -30,4 +45,15 @@ class UserFolderStorage extends FolderStorage
$row['access'] = $access;
}
}
/**
* @param array $options
* @return void
*/
protected function initOptions(array $options): void
{
parent::initOptions($options);
$this->caseSensitive = $options['case_sensitive'] ?? false;
}
}

View File

@@ -43,7 +43,7 @@ class UserCollection extends FlexCollection implements UserCollectionInterface
public function load($username): UserInterface
{
if ($username !== '') {
$key = mb_strtolower($username);
$key = $this->filterUsername($username);
$user = $this->get($key);
if ($user) {
return $user;
@@ -84,7 +84,7 @@ class UserCollection extends FlexCollection implements UserCollectionInterface
} elseif ($field === 'flex_key') {
$user = $this->withKeyField('flex_key')->get($query);
} elseif ($field === 'username') {
$user = $this->get(mb_strtolower($query));
$user = $this->get($this->filterUsername($query));
} else {
$user = parent::find($query, $field);
}
@@ -114,4 +114,18 @@ class UserCollection extends FlexCollection implements UserCollectionInterface
return $exists;
}
/**
* @param string $key
* @return bool|false|string|string[]|null
*/
protected function filterUsername(string $key)
{
$storage = $this->getFlexDirectory()->getStorage();
if (method_exists($storage, 'normalizeKey')) {
return $storage->normalizeKey($key);
}
return mb_strtolower($key);
}
}

View File

@@ -53,12 +53,13 @@ class UserIndex extends FlexIndex
/**
* @param array $meta
* @param array $data
* @param FlexStorageInterface $storage
*/
public static function updateObjectMeta(array &$meta, array $data)
public static function updateObjectMeta(array &$meta, array $data, FlexStorageInterface $storage)
{
// Username can also be number and stored as such.
$key = (string)($data['username'] ?? $meta['key'] ?? $meta['storage_key']);
$meta['key'] = mb_strtolower($key);
$meta['key'] = static::filterUsername($key, $storage);
$meta['email'] = isset($data['email']) ? mb_strtolower($data['email']) : null;
}
@@ -73,7 +74,7 @@ class UserIndex extends FlexIndex
public function load($username): UserInterface
{
if ($username !== '') {
$key = mb_strtolower($username);
$key = static::filterUsername($username, $this->getFlexDirectory()->getStorage());
$user = $this->get($key);
if ($user) {
return $user;
@@ -116,7 +117,7 @@ class UserIndex extends FlexIndex
} elseif ($field === 'email') {
$user = $this->withKeyField('email')->get($query);
} elseif ($field === 'username') {
$user = $this->get(mb_strtolower($query));
$user = $this->get(static::filterUsername($query, $this->getFlexDirectory()->getStorage()));
} else {
$user = $this->__call('find', [$query, $field]);
}
@@ -129,6 +130,20 @@ class UserIndex extends FlexIndex
return $this->load('');
}
/**
* @param string $key
* @param FlexStorageInterface $storage
* @return string
*/
protected static function filterUsername(string $key, FlexStorageInterface $storage): string
{
if ($storage && \method_exists($storage, 'normalizeKey')) {
return $storage->normalizeKey($key);
}
return mb_strtolower($key);
}
/**
* @param FlexStorageInterface $storage
* @return CompiledYamlFile|null

View File

@@ -116,11 +116,11 @@ class User extends Data implements UserInterface
}
if ($file) {
$username = $this->get('username');
$username = $this->filterUsername($this->get('username'));
if (!$file->filename()) {
$locator = Grav::instance()['locator'];
$file->filename($locator->findResource('account://' . mb_strtolower($username) . YAML_EXT, true, true));
$file->filename($locator->findResource('account://' . $username . YAML_EXT, true, true));
}
// if plain text password, hash it and remove plain text
@@ -176,6 +176,8 @@ class User extends Data implements UserInterface
/**
* Serialize user.
*
* @return array
*/
public function __sleep()
{
@@ -272,6 +274,18 @@ class User extends Data implements UserInterface
return parent::count();
}
/**
* @param string $username
* @return string
*/
protected function filterUsername(string $username): string
{
return mb_strtolower($username);
}
/**
* @return string|null
*/
protected function getAvatarFile(): ?string
{
$avatars = $this->get('avatar');

View File

@@ -45,8 +45,8 @@ class UserCollection implements UserCollectionInterface
/** @var UniformResourceLocator $locator */
$locator = $grav['locator'];
// force lowercase of username
$username = mb_strtolower($username);
// Filter username.
$username = $this->filterUsername($username);
$filename = 'account://' . $username . YAML_EXT;
$path = $locator->findResource($filename) ?: $locator->findResource($filename, true, true);
@@ -138,4 +138,14 @@ class UserCollection implements UserCollectionInterface
return count($accounts);
}
/**
* @param string $username
* @return string
*/
protected function filterUsername(string $username): string
{
return mb_strtolower($username);
}
}

View File

@@ -20,7 +20,6 @@ use Grav\Framework\Flex\Interfaces\FlexCollectionInterface;
use Grav\Framework\Flex\Interfaces\FlexIndexInterface;
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
use Grav\Framework\Flex\Interfaces\FlexStorageInterface;
use Grav\Framework\Object\Interfaces\ObjectCollectionInterface;
use Grav\Framework\Object\Interfaces\ObjectInterface;
use Grav\Framework\Object\ObjectIndex;
use Monolog\Logger;
@@ -77,8 +76,9 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
*
* @param array $meta
* @param array $data
* @param FlexStorageInterface $storage
*/
public static function updateObjectMeta(array &$meta, array $data)
public static function updateObjectMeta(array &$meta, array $data, FlexStorageInterface $storage)
{
// For backwards compatibility, no need to call this method when you override this method.
static::updateIndexData($meta, $data);
@@ -709,7 +709,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
if ($keyField !== 'storage_key' && isset($row[$keyField])) {
$entry['key'] = $row[$keyField];
}
static::updateObjectMeta($entry, $row ?? []);
static::updateObjectMeta($entry, $row ?? [], $storage);
if (isset($row['__ERROR'])) {
$entry['__ERROR'] = true;
static::onException(new \RuntimeException(sprintf('Object failed to load: %s (%s)', $key,

View File

@@ -623,7 +623,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
if ($meta) {
/** @var FlexIndex $indexClass */
$indexClass = $this->getFlexDirectory()->getIndexClass();
$indexClass::updateObjectMeta($meta, $value);
$indexClass::updateObjectMeta($meta, $value, $storage);
$this->_meta = $meta;
}