From 1292722ac3b3ceeb65777f35a1d168b6a674fe96 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Thu, 6 Apr 2023 19:19:04 +0200 Subject: [PATCH] Add Username validation --- config/config.default.php | 4 ++ includes/model/User_model.php | 21 ------ includes/pages/admin_user.php | 10 ++- includes/pages/guest_login.php | 11 +-- resources/lang/de_DE/default.po | 8 +-- src/Http/Validation/Rules/Username.php | 28 ++++++++ .../Http/Validation/Rules/UsernameTest.php | 71 +++++++++++++++++++ 7 files changed, 118 insertions(+), 35 deletions(-) create mode 100644 src/Http/Validation/Rules/Username.php create mode 100644 tests/Unit/Http/Validation/Rules/UsernameTest.php diff --git a/config/config.default.php b/config/config.default.php index d7e31ac6..f29d8044 100644 --- a/config/config.default.php +++ b/config/config.default.php @@ -266,6 +266,10 @@ return [ // Whether the mobile number can be shown to other users '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 'enable_user_name' => (bool) env('ENABLE_USER_NAME', false), diff --git a/includes/model/User_model.php b/includes/model/User_model.php index b57059d3..ff1d76ed 100644 --- a/includes/model/User_model.php +++ b/includes/model/User_model.php @@ -67,27 +67,6 @@ function Users_by_angeltype_inverted(AngelType $angeltype) ->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 * diff --git a/includes/pages/admin_user.php b/includes/pages/admin_user.php index 93ac2f09..3d2a23ae 100644 --- a/includes/pages/admin_user.php +++ b/includes/pages/admin_user.php @@ -1,6 +1,7 @@ settings->email_human) { $user_source->email = $request->postData('eemail'); } - $nickValidation = User_validate_Nick($request->postData('eNick')); - if ($nickValidation->isValid()) { - $user_source->name = $nickValidation->getValue(); + + $nick = trim($request->get('eNick')); + $nickValid = (new Username())->validate($nick); + + if ($nickValid) { + $user_source->name = $nick; } $user_source->save(); diff --git a/includes/pages/guest_login.php b/includes/pages/guest_login.php index 9353b4c0..fd54977c 100644 --- a/includes/pages/guest_login.php +++ b/includes/pages/guest_login.php @@ -4,6 +4,7 @@ use Carbon\Carbon; use Engelsystem\Database\Database; use Engelsystem\Events\Listener\OAuth2; use Engelsystem\Config\GoodieType; +use Engelsystem\Http\Validation\Rules\Username; use Engelsystem\Models\AngelType; use Engelsystem\Models\Group; use Engelsystem\Models\OAuth; @@ -114,13 +115,13 @@ function guest_register() $valid = true; if ($request->has('username')) { - $nickValidation = User_validate_Nick($request->input('username')); - $nick = $nickValidation->getValue(); + $nick = trim($request->get('username')); + $nickValid = (new Username())->validate($nick); - if (!$nickValidation->isValid()) { + if (!$nickValid) { $valid = false; $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 ), true); } @@ -403,7 +404,7 @@ function guest_register() ), 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.') ), ]), diff --git a/resources/lang/de_DE/default.po b/resources/lang/de_DE/default.po index d5e96a22..e4335fe4 100644 --- a/resources/lang/de_DE/default.po +++ b/resources/lang/de_DE/default.po @@ -1533,12 +1533,8 @@ msgstr "Gib bitte einen erlaubten Nick an." #: includes/pages/guest_login.php:77 includes/pages/guest_login.php:277 #: includes/view/User_view.php:42 -msgid "" -"Use up to 24 letters, numbers, connecting punctuations or spaces for your " -"nickname." -msgstr "" -"Verwende bis zu 24 Buchstaben, Zahlen, verbindende Schriftzeichen (.-_) oder " -"Leerzeichen für deinen Nick." +msgid "Use up to 24 letters, numbers or connecting punctuations for your nickname." +msgstr "Verwende bis zu 24 Buchstaben, Zahlen oder verbindende Schriftzeichen (.-_) für deinen Nick." #: includes/pages/guest_login.php:82 #, php-format diff --git a/src/Http/Validation/Rules/Username.php b/src/Http/Validation/Rules/Username.php new file mode 100644 index 00000000..ff9b7cea --- /dev/null +++ b/src/Http/Validation/Rules/Username.php @@ -0,0 +1,28 @@ +validate($input) + && Validator::not(Validator::regex($regex))->validate($input); + } +} diff --git a/tests/Unit/Http/Validation/Rules/UsernameTest.php b/tests/Unit/Http/Validation/Rules/UsernameTest.php new file mode 100644 index 00000000..47b9f84b --- /dev/null +++ b/tests/Unit/Http/Validation/Rules/UsernameTest.php @@ -0,0 +1,71 @@ +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 + */ + 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'); + } +}