Add Username validation

This commit is contained in:
Michael Weimann 2023-04-06 19:19:04 +02:00 committed by Igor Scheller
parent 57940cf570
commit 1292722ac3
7 changed files with 118 additions and 35 deletions

View File

@ -266,6 +266,10 @@ return [
// Whether the mobile number can be shown to other users // Whether the mobile number can be shown to other users
'enable_mobile_show' => (bool) env('ENABLE_MOBILE_SHOW', false), 'enable_mobile_show' => (bool) env('ENABLE_MOBILE_SHOW', false),
// Regular expression describing a FALSE username.
// Per default usernames must only contain alphanumeric chars, "-", "_" or ".".
'username_regex' => (string) env('USERNAME_REGEX', '/([^\p{L}\p{N}\-_.]+)/ui'),
// Enables first name and last name // Enables first name and last name
'enable_user_name' => (bool) env('ENABLE_USER_NAME', false), 'enable_user_name' => (bool) env('ENABLE_USER_NAME', false),

View File

@ -67,27 +67,6 @@ function Users_by_angeltype_inverted(AngelType $angeltype)
->get(); ->get();
} }
/**
* Strip unwanted characters from a users nick. Allowed are letters, numbers, connecting punctuation and simple space.
* Nick is trimmed.
*
* @param string $nick
* @return ValidationResult
*/
function User_validate_Nick($nick)
{
$nick = trim($nick);
if (strlen($nick) == 0 || strlen($nick) > 24) {
return new ValidationResult(false, $nick);
}
if (preg_match(config('username_regex', '/([^\p{L}\p{N}\-_. ]+)/ui'), $nick)) {
return new ValidationResult(false, $nick);
}
return new ValidationResult(true, $nick);
}
/** /**
* Validate the planned arrival date * Validate the planned arrival date
* *

View File

@ -1,6 +1,7 @@
<?php <?php
use Engelsystem\Config\GoodieType; use Engelsystem\Config\GoodieType;
use Engelsystem\Http\Validation\Rules\Username;
use Engelsystem\Models\Group; use Engelsystem\Models\Group;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
@ -244,9 +245,12 @@ function admin_user()
if ($user_source->settings->email_human) { if ($user_source->settings->email_human) {
$user_source->email = $request->postData('eemail'); $user_source->email = $request->postData('eemail');
} }
$nickValidation = User_validate_Nick($request->postData('eNick'));
if ($nickValidation->isValid()) { $nick = trim($request->get('eNick'));
$user_source->name = $nickValidation->getValue(); $nickValid = (new Username())->validate($nick);
if ($nickValid) {
$user_source->name = $nick;
} }
$user_source->save(); $user_source->save();

View File

@ -4,6 +4,7 @@ use Carbon\Carbon;
use Engelsystem\Database\Database; use Engelsystem\Database\Database;
use Engelsystem\Events\Listener\OAuth2; use Engelsystem\Events\Listener\OAuth2;
use Engelsystem\Config\GoodieType; use Engelsystem\Config\GoodieType;
use Engelsystem\Http\Validation\Rules\Username;
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\Group; use Engelsystem\Models\Group;
use Engelsystem\Models\OAuth; use Engelsystem\Models\OAuth;
@ -114,13 +115,13 @@ function guest_register()
$valid = true; $valid = true;
if ($request->has('username')) { if ($request->has('username')) {
$nickValidation = User_validate_Nick($request->input('username')); $nick = trim($request->get('username'));
$nick = $nickValidation->getValue(); $nickValid = (new Username())->validate($nick);
if (!$nickValidation->isValid()) { if (!$nickValid) {
$valid = false; $valid = false;
$msg .= error(sprintf( $msg .= error(sprintf(
__('Please enter a valid nick.') . ' ' . __('Use up to 24 letters, numbers, connecting punctuations or spaces for your nickname.'), __('Please enter a valid nick.') . ' ' . __('Use up to 24 letters, numbers or connecting punctuations for your nickname.'),
$nick $nick
), true); ), true);
} }
@ -403,7 +404,7 @@ function guest_register()
), ),
form_info( form_info(
'', '',
__('Use up to 24 letters, numbers, connecting punctuations or spaces for your nickname.') __('Use up to 24 letters, numbers or connecting punctuations for your nickname.')
), ),
]), ]),

View File

@ -1533,12 +1533,8 @@ msgstr "Gib bitte einen erlaubten Nick an."
#: includes/pages/guest_login.php:77 includes/pages/guest_login.php:277 #: includes/pages/guest_login.php:77 includes/pages/guest_login.php:277
#: includes/view/User_view.php:42 #: includes/view/User_view.php:42
msgid "" msgid "Use up to 24 letters, numbers or connecting punctuations for your nickname."
"Use up to 24 letters, numbers, connecting punctuations or spaces for your " msgstr "Verwende bis zu 24 Buchstaben, Zahlen oder verbindende Schriftzeichen (.-_) für deinen Nick."
"nickname."
msgstr ""
"Verwende bis zu 24 Buchstaben, Zahlen, verbindende Schriftzeichen (.-_) oder "
"Leerzeichen für deinen Nick."
#: includes/pages/guest_login.php:82 #: includes/pages/guest_login.php:82
#, php-format #, php-format

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Http\Validation\Rules;
use Respect\Validation\Rules\AbstractRule;
use Respect\Validation\Validator;
use RuntimeException;
/**
* Username validation.
* Usernames must have 1-24 chars and NOT match the regular expression defined under the config key "username_regex".
*/
class Username extends AbstractRule
{
public function validate(mixed $input): bool
{
$regex = config('username_regex');
if ($regex === null) {
throw new RuntimeException('username_regex not set in config');
}
return Validator::length(1, 24)->validate($input)
&& Validator::not(Validator::regex($regex))->validate($input);
}
}

View File

@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Test\Unit\Http\Validation\Rules;
use Engelsystem\Application;
use Engelsystem\Config\Config;
use Engelsystem\Http\Validation\Rules\Username;
use Engelsystem\Test\Unit\ServiceProviderTest;
use RuntimeException;
class UsernameTest extends ServiceProviderTest
{
private Username $subject;
private Config $config;
public function setUp(): void
{
$this->subject = new Username();
$app = $this->getApp([]);
$this->config = new Config([]);
$app->instance('config', $this->config);
$app->get('config');
Application::setInstance($app);
// load "username_regex" from the default config
$defaultConfig = include __DIR__ . '/../../../../../config/config.default.php';
$this->config->set('username_regex', $defaultConfig['username_regex']);
}
/**
* @return array<string,array{string,bool}>
*/
public function provideValidateWithDefaultConfigTestData(): array
{
return [
'empty string' => ['', false],
'max length exceeded' => [str_repeat('1', 25), false],
'invalid char !' => ['abc!!!', false],
'space' => ['ab c', false],
'valid Greek letters' => ['λουκάνικο', true],
'min length valid' => ['a', true],
'valid with all chars' => ['abc123_-.jkl', true],
'valid with accents' => ['café', true],
'max length valid' => [str_repeat('a', 24), true],
];
}
/**
* @covers \Engelsystem\Http\Validation\Rules\Username::validate
* @dataProvider provideValidateWithDefaultConfigTestData
*/
public function testValidateWithDefaultConfig(mixed $value, bool $expectedValid): void
{
self::assertSame($expectedValid, $this->subject->validate($value));
}
/**
* @covers \Engelsystem\Http\Validation\Rules\Username::validate
*/
public function testMissingConfigRaisesException(): void
{
$this->config->set('username_regex', null);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('username_regex not set in config');
$this->subject->validate('test');
}
}