diff --git a/app/Events/Security/User/UserKeepsFailingMFA.php b/app/Events/Security/User/UserKeepsFailingMFA.php new file mode 100644 index 0000000000..665bc83b04 --- /dev/null +++ b/app/Events/Security/User/UserKeepsFailingMFA.php @@ -0,0 +1,45 @@ +. + */ + +namespace FireflyIII\Events\Security\User; + +use FireflyIII\Events\Event; +use FireflyIII\User; +use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Queue\SerializesModels; +use InvalidArgumentException; + +class UserKeepsFailingMFA extends Event +{ + use SerializesModels; + + public User $user; + + public function __construct(Authenticatable|User|null $user, public int $count) + { + if ($user instanceof User) { + $this->user = $user; + return; + } + throw new InvalidArgumentException('User must be an instance of User.'); + } +} + diff --git a/app/Handlers/Events/Security/MFAHandler.php b/app/Handlers/Events/Security/MFAHandler.php index 60659098d6..e6b22ae917 100644 --- a/app/Handlers/Events/Security/MFAHandler.php +++ b/app/Handlers/Events/Security/MFAHandler.php @@ -38,28 +38,7 @@ class MFAHandler { public function sendMFAFailedAttemptsMail(MFAManyFailedAttempts $event): void { - Log::debug(sprintf('Now in %s', __METHOD__)); - $user = $event->user; - $count = $event->count; - - try { - Notification::send($user, new MFAManyFailedAttemptsNotification($user, $count)); - } catch (Exception $e) { - $message = $e->getMessage(); - if (str_contains($message, 'Bcc')) { - Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.'); - - return; - } - if (str_contains($message, 'RFC 2822')) { - Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.'); - - return; - } - Log::error($e->getMessage()); - Log::error($e->getTraceAsString()); - } } public function sendNewMFABackupCodesMail(MFANewBackupCodes $event): void diff --git a/app/Http/Controllers/Auth/TwoFactorController.php b/app/Http/Controllers/Auth/TwoFactorController.php index 6c39a4e6d2..fbe21d6e81 100644 --- a/app/Http/Controllers/Auth/TwoFactorController.php +++ b/app/Http/Controllers/Auth/TwoFactorController.php @@ -28,6 +28,7 @@ use FireflyIII\Events\Security\MFAManyFailedAttempts; use FireflyIII\Events\Security\MFAUsedBackupCode; use FireflyIII\Events\Security\User\UserHasFewMFABackupCodesLeft; use FireflyIII\Events\Security\User\UserHasNoMFABackupCodesLeft; +use FireflyIII\Events\Security\User\UserKeepsFailingMFA; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Support\Facades\Preferences; use FireflyIII\User; @@ -88,7 +89,7 @@ class TwoFactorController extends Controller if (3 === $counter || 10 === $counter) { // do not reset MFA failure counter, but DO send a warning to the user. Log::channel('audit')->info(sprintf('User "%s" has had %d failed MFA attempts.', $user->email, $counter)); - event(new MFAManyFailedAttempts($user, $counter)); + event(new UserKeepsFailingMFA($user, $counter)); } unset($user); } diff --git a/app/Listeners/Security/User/NotifiesUserAboutRepeatedMFAFailures.php b/app/Listeners/Security/User/NotifiesUserAboutRepeatedMFAFailures.php new file mode 100644 index 0000000000..4d495d6fe2 --- /dev/null +++ b/app/Listeners/Security/User/NotifiesUserAboutRepeatedMFAFailures.php @@ -0,0 +1,58 @@ +. + */ + +namespace FireflyIII\Listeners\Security\User; + +use Exception; +use FireflyIII\Events\Security\User\UserKeepsFailingMFA; +use FireflyIII\Notifications\Security\MFAManyFailedAttemptsNotification; +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Notification; + +class NotifiesUserAboutRepeatedMFAFailures +{ + public function handle(UserKeepsFailingMFA $event): void + { + Log::debug(sprintf('Now in %s', __METHOD__)); + + $user = $event->user; + $count = $event->count; + + try { + Notification::send($user, new MFAManyFailedAttemptsNotification($user, $count)); + } catch (Exception $e) { + $message = $e->getMessage(); + if (str_contains($message, 'Bcc')) { + Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.'); + + return; + } + if (str_contains($message, 'RFC 2822')) { + Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.'); + + return; + } + Log::error($e->getMessage()); + Log::error($e->getTraceAsString()); + } + } + +} diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 2ac881c1e7..e82d556da3 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -197,9 +197,9 @@ class EventServiceProvider extends ServiceProvider // MFABackupNoLeft::class => [ // 'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupNoLeftMail', // ], - MFAManyFailedAttempts::class => [ - 'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAFailedAttemptsMail', - ], +// MFAManyFailedAttempts::class => [ +// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAFailedAttemptsMail', +// ], // preferences UserGroupChangedPrimaryCurrency::class => [ 'FireflyIII\Handlers\Events\PreferencesEventHandler@resetPrimaryCurrencyAmounts',