├── LICENSE ├── Mailer ├── AuthCodeMailerInterface.php └── SymfonyAuthCodeMailer.php ├── Model └── Email │ └── TwoFactorInterface.php ├── README.md ├── Security └── TwoFactor │ ├── Event │ └── EmailCodeEvents.php │ └── Provider │ └── Email │ ├── EmailTwoFactorProvider.php │ └── Generator │ ├── CodeGenerator.php │ └── CodeGeneratorInterface.php └── composer.json /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Christian Scheb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Mailer/AuthCodeMailerInterface.php: -------------------------------------------------------------------------------- 1 | senderAddress = new Address($senderEmail, $senderName); 26 | } elseif (null !== $senderEmail && $senderEmail) { 27 | $this->senderAddress = $senderEmail; 28 | } 29 | } 30 | 31 | public function sendAuthCode(TwoFactorInterface $user): void 32 | { 33 | $authCode = $user->getEmailAuthCode(); 34 | if (null === $authCode) { 35 | return; 36 | } 37 | 38 | $message = new Email(); 39 | $message 40 | ->to($user->getEmailAuthRecipient()) 41 | ->subject('Authentication Code') 42 | ->text($authCode); 43 | 44 | if (null !== $this->senderAddress) { 45 | $message->from($this->senderAddress); 46 | } 47 | 48 | $this->mailer->send($message); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Model/Email/TwoFactorInterface.php: -------------------------------------------------------------------------------- 1 | getUser(); 33 | 34 | return $user instanceof TwoFactorInterface && $user->isEmailAuthEnabled(); 35 | } 36 | 37 | public function prepareAuthentication(object $user): void 38 | { 39 | if (!($user instanceof TwoFactorInterface)) { 40 | return; 41 | } 42 | 43 | $this->codeGenerator->generateAndSend($user); 44 | 45 | $event = new TwoFactorCodeEvent($user, $user->getEmailAuthCode() ?? ''); 46 | $this->eventDispatcher->dispatch($event, EmailCodeEvents::SENT); 47 | } 48 | 49 | public function validateAuthenticationCode(object $user, string $authenticationCode): bool 50 | { 51 | if (!($user instanceof TwoFactorInterface)) { 52 | return false; 53 | } 54 | 55 | $event = new TwoFactorCodeEvent($user, $authenticationCode); 56 | $this->eventDispatcher->dispatch($event, EmailCodeEvents::CHECK); 57 | 58 | // Strip any user added spaces 59 | $authenticationCode = str_replace(' ', '', $authenticationCode); 60 | $isValid = $user->getEmailAuthCode() === $authenticationCode; 61 | $this->eventDispatcher->dispatch($event, $isValid ? EmailCodeEvents::VALID : EmailCodeEvents::INVALID); 62 | 63 | return $isValid; 64 | } 65 | 66 | public function getFormRenderer(): TwoFactorFormRendererInterface 67 | { 68 | return $this->formRenderer; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Security/TwoFactor/Provider/Email/Generator/CodeGenerator.php: -------------------------------------------------------------------------------- 1 | digits - 1); 27 | $max = 10 ** $this->digits - 1; 28 | $code = $this->generateCode($min, $max); 29 | $user->setEmailAuthCode((string) $code); 30 | $this->persister->persist($user); 31 | $this->mailer->sendAuthCode($user); 32 | } 33 | 34 | public function reSend(TwoFactorInterface $user): void 35 | { 36 | $this->mailer->sendAuthCode($user); 37 | } 38 | 39 | protected function generateCode(int $min, int $max): int 40 | { 41 | return random_int($min, $max); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Security/TwoFactor/Provider/Email/Generator/CodeGeneratorInterface.php: -------------------------------------------------------------------------------- 1 |