From 64c036a038d79818db00d102b77675fbbfb3007f Mon Sep 17 00:00:00 2001 From: krm-shrftdnv Date: Wed, 10 Apr 2024 17:33:56 +0300 Subject: [PATCH 1/2] created new lowercase filter --- api/src/DTO/ResetPassword.php | 1 + api/src/Entity/CampCollaboration.php | 1 + api/src/Entity/Profile.php | 2 + api/src/InputFilter/Lowercase.php | 13 ++++ api/src/InputFilter/LowercaseFilter.php | 30 +++++++ .../Security/OAuth/GoogleAuthenticator.php | 3 +- .../Security/OAuth/HitobitoAuthenticator.php | 3 +- .../CreateCampCollaborationTest.php | 23 ++++++ .../Api/ResetPassword/ResetPasswordTest.php | 18 +++++ api/tests/Api/Users/CreateUserTest.php | 28 +++++++ api/tests/InputFilter/LowercaseFilterTest.php | 78 +++++++++++++++++++ 11 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 api/src/InputFilter/Lowercase.php create mode 100644 api/src/InputFilter/LowercaseFilter.php create mode 100644 api/tests/InputFilter/LowercaseFilterTest.php diff --git a/api/src/DTO/ResetPassword.php b/api/src/DTO/ResetPassword.php index 3445e30fad..7bd261031a 100644 --- a/api/src/DTO/ResetPassword.php +++ b/api/src/DTO/ResetPassword.php @@ -51,6 +51,7 @@ class ResetPassword { public ?string $id = null; #[InputFilter\Trim] + #[InputFilter\Lowercase] #[ApiProperty(readable: true, writable: true)] #[Groups(['create', 'read'])] public ?string $email = null; diff --git a/api/src/Entity/CampCollaboration.php b/api/src/Entity/CampCollaboration.php index d26edbe1fb..72f6a11515 100644 --- a/api/src/Entity/CampCollaboration.php +++ b/api/src/Entity/CampCollaboration.php @@ -131,6 +131,7 @@ class CampCollaboration extends BaseEntity implements BelongsToCampInterface { * a user account. Either this field or the user field should be null. */ #[InputFilter\Trim] + #[InputFilter\Lowercase] #[Assert\Email] #[Assert\Length(min: 1, max: 128)] #[AssertEitherIsNull(other: 'user')] diff --git a/api/src/Entity/Profile.php b/api/src/Entity/Profile.php index 536f67adba..52ccf5b924 100644 --- a/api/src/Entity/Profile.php +++ b/api/src/Entity/Profile.php @@ -53,6 +53,7 @@ class Profile extends BaseEntity { * Can only be changed by setting the newEmail field, which triggers an email verification flow. */ #[InputFilter\Trim] + #[InputFilter\Lowercase] #[Assert\NotBlank] #[Assert\Email] #[ApiProperty(example: self::EXAMPLE_EMAIL)] @@ -65,6 +66,7 @@ class Profile extends BaseEntity { * If set, a verification email is sent to this email address. */ #[InputFilter\Trim] + #[InputFilter\Lowercase] #[Assert\Email] #[ApiProperty(example: self::EXAMPLE_EMAIL)] #[Groups(['write'])] diff --git a/api/src/InputFilter/Lowercase.php b/api/src/InputFilter/Lowercase.php new file mode 100644 index 0000000000..ebb402ac91 --- /dev/null +++ b/api/src/InputFilter/Lowercase.php @@ -0,0 +1,13 @@ +findOneBy(['email' => $email]); + $profiles = $profileRepository->findBy(['email' => strtolower($email)]); + $profile = count($profiles) > 0 ? $profiles[0] : null; $user = $profile?->user; if (is_null($profile)) { diff --git a/api/src/Security/OAuth/HitobitoAuthenticator.php b/api/src/Security/OAuth/HitobitoAuthenticator.php index 7b814e570e..85a350404b 100644 --- a/api/src/Security/OAuth/HitobitoAuthenticator.php +++ b/api/src/Security/OAuth/HitobitoAuthenticator.php @@ -63,7 +63,8 @@ public function authenticate(Request $request): Passport { } // do we have a matching user by email? - $profile = $profileRepository->findOneBy(['email' => $email]); + $profiles = $profileRepository->findBy(['email' => strtolower($email)]); + $profile = count($profiles) > 0 ? $profiles[0] : null; $user = $profile?->user; if (is_null($profile)) { diff --git a/api/tests/Api/CampCollaborations/CreateCampCollaborationTest.php b/api/tests/Api/CampCollaborations/CreateCampCollaborationTest.php index 527af5f829..e37432115e 100644 --- a/api/tests/Api/CampCollaborations/CreateCampCollaborationTest.php +++ b/api/tests/Api/CampCollaborations/CreateCampCollaborationTest.php @@ -257,6 +257,29 @@ public function testCreateCampCollaborationTrimsInviteEmail() { ])); } + public function testCreateCampCollaborationLowercasesInviteEmail(): void { + static::createClientWithCredentials()->request( + 'POST', + '/camp_collaborations', + [ + 'json' => $this->getExampleWritePayload( + [ + 'inviteEmail' => 'sOmeonE@example.COM', + ], + ['user'] + ), + ] + ); + + $this->assertResponseStatusCodeSame(201); + $this->assertJsonContains($this->getExampleReadPayload([ + 'inviteEmail' => 'someone@example.com', + '_links' => [ + 'user' => null, + ], + ])); + } + public function testCreateCampCollaborationWithInviteEmailInsteadOfUserIsPossible() { static::createClientWithCredentials()->request('POST', '/camp_collaborations', ['json' => $this->getExampleWritePayload([ 'inviteEmail' => 'someone@example.com', diff --git a/api/tests/Api/ResetPassword/ResetPasswordTest.php b/api/tests/Api/ResetPassword/ResetPasswordTest.php index 5e5d087a25..882fc7ea80 100644 --- a/api/tests/Api/ResetPassword/ResetPasswordTest.php +++ b/api/tests/Api/ResetPassword/ResetPasswordTest.php @@ -107,6 +107,24 @@ public function testPostResetPasswordTrimsEmail() { self::assertEmailCount(1); } + public function testPostResetPasswordLowercasesEmail() { + /** @var User $user */ + $user = static::getFixture('user1manager'); + + $this->createBasicClient()->request( + 'POST', + '/auth/reset_password', + [ + 'json' => [ + 'email' => strtoupper("{$user->getEmail()}"), + ], + ] + ); + + $this->assertResponseStatusCodeSame(204); + self::assertEmailCount(1); + } + public function testPostResetPasswordReturns204ForUnknownEmailButSendsNoEmails() { $this->createBasicClient()->request( 'POST', diff --git a/api/tests/Api/Users/CreateUserTest.php b/api/tests/Api/Users/CreateUserTest.php index bc22473620..7b422b4ccd 100644 --- a/api/tests/Api/Users/CreateUserTest.php +++ b/api/tests/Api/Users/CreateUserTest.php @@ -208,6 +208,34 @@ public function testCreateUserTrimsEmail() { )); } + public function testCreateUserLowercaseEmail(): void { + static::createBasicClient()->request( + 'POST', + '/users', + [ + 'json' => $this->getExampleWritePayload( + mergeEmbeddedAttributes: [ + 'profile' => [ + 'email' => 'Bi-pi@example.COM', + ], + ] + ), + ] + ); + + $this->assertResponseStatusCodeSame(201); + $this->assertJsonContains($this->getExampleReadPayload( + [ + '_embedded' => [ + 'profile' => [ + 'email' => 'bi-pi@example.com', + ], + ], + ], + ['password'] + )); + } + public function testCreateUserValidatesMissingEmail() { // use this easy way here, because unsetting a nested attribute would be complicated $exampleWritePayload = $this->getExampleWritePayload(); diff --git a/api/tests/InputFilter/LowercaseFilterTest.php b/api/tests/InputFilter/LowercaseFilterTest.php new file mode 100644 index 0000000000..f5b6906445 --- /dev/null +++ b/api/tests/InputFilter/LowercaseFilterTest.php @@ -0,0 +1,78 @@ + $input]; + $outputData = ['key' => $output]; + $trim = new LowercaseFilter(); + + // when + $result = $trim->applyTo($data, 'key'); + + // then + $this->assertEquals($outputData, $result); + } + + public static function getExamples(): array { + return [ + ['', ''], + ['abc', 'abc'], + ['AbC', 'abc'], + ['This Is A Test', 'this is a test'], + ['TeSt123', 'test123'], + ['ÁccèntS', 'áccènts'], + ['Test@Example.com', 'test@example.com'], + ['JohnDoe@GMail.COM', 'johndoe@gmail.com'], + ['USER-NAME+TAG@EXAMPLE.NET', 'user-name+tag@example.net'], + ['info@sub.domain.COM', 'info@sub.domain.com'], + ]; + } + + public function testDoesNothingWhenKeyIsMissing(): void { + // given + $data = ['otherkey' => 'something']; + $lowercase = new LowercaseFilter(); + + // when + $result = $lowercase->applyTo($data, 'key'); + + // then + $this->assertEquals($data, $result); + } + + public function testDoesNothingWhenValueIsNull(): void { + // given + $data = ['key' => null]; + $trim = new LowercaseFilter(); + + // when + $result = $trim->applyTo($data, 'key'); + + // then + $this->assertEquals($data, $result); + } + + public function testThrowsWhenValueIsNotStringable(): void { + // given + $data = ['key' => new \stdClass()]; + $trim = new LowercaseFilter(); + + // then + $this->expectException(UnexpectedValueException::class); + + // when + $trim->applyTo($data, 'key'); + } +} From de508c3f0329847c87c821e24adfe3f9222a4a0a Mon Sep 17 00:00:00 2001 From: krm_shrftdnv Date: Wed, 10 Apr 2024 20:30:43 +0300 Subject: [PATCH 2/2] fixed test --- api/tests/InputFilter/LowercaseFilterTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/api/tests/InputFilter/LowercaseFilterTest.php b/api/tests/InputFilter/LowercaseFilterTest.php index f5b6906445..14554f4eda 100644 --- a/api/tests/InputFilter/LowercaseFilterTest.php +++ b/api/tests/InputFilter/LowercaseFilterTest.php @@ -32,7 +32,6 @@ public static function getExamples(): array { ['AbC', 'abc'], ['This Is A Test', 'this is a test'], ['TeSt123', 'test123'], - ['ÁccèntS', 'áccènts'], ['Test@Example.com', 'test@example.com'], ['JohnDoe@GMail.COM', 'johndoe@gmail.com'], ['USER-NAME+TAG@EXAMPLE.NET', 'user-name+tag@example.net'],