Merge branch 'develop' into dependabot/npm_and_yarn/develop/i18next-chained-backend-5.0.0

This commit is contained in:
mergify[bot]
2026-01-19 18:57:51 +00:00
committed by GitHub
5 changed files with 108 additions and 25 deletions
@@ -0,0 +1,45 @@
<?php
/*
* UserKeepsFailingMFA.php
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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.');
}
}
@@ -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
@@ -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);
}
@@ -0,0 +1,58 @@
<?php
/*
* NotifiesUserAboutRepeatedMFAFailures.php
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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());
}
}
}
+3 -3
View File
@@ -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',