mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-07-27 16:07:45 -07:00
Merge branch 'develop' into dependabot/npm_and_yarn/develop/jquery-4.0.0
This commit is contained in:
+8
-8
@@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* EnabledMFA.php
|
||||
* Copyright (c) 2024 james@firefly-iii.org.
|
||||
* UserHasFewMFABackupCodesLeft.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -17,19 +16,18 @@
|
||||
* 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/.
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events\Security;
|
||||
namespace FireflyIII\Events\Security\User;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class MFABackupFewLeft extends Event
|
||||
class UserHasFewMFABackupCodesLeft extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
@@ -39,6 +37,8 @@ class MFABackupFewLeft extends Event
|
||||
{
|
||||
if ($user instanceof User) {
|
||||
$this->user = $user;
|
||||
return;
|
||||
}
|
||||
throw new InvalidArgumentException('User must be an instance of User.');
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* EnabledMFA.php
|
||||
* Copyright (c) 2024 james@firefly-iii.org.
|
||||
* UserHasNoMFABackupCodesLeft.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -17,19 +16,18 @@
|
||||
* 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/.
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events\Security;
|
||||
namespace FireflyIII\Events\Security\User;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class MFABackupNoLeft extends Event
|
||||
class UserHasNoMFABackupCodesLeft extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
@@ -39,6 +37,8 @@ class MFABackupNoLeft extends Event
|
||||
{
|
||||
if ($user instanceof User) {
|
||||
$this->user = $user;
|
||||
return;
|
||||
}
|
||||
throw new InvalidArgumentException('User must be an instance of User.');
|
||||
}
|
||||
}
|
||||
@@ -25,13 +25,9 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Handlers\Events\Security;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\MFABackupFewLeft;
|
||||
use FireflyIII\Events\Security\MFABackupNoLeft;
|
||||
use FireflyIII\Events\Security\MFAManyFailedAttempts;
|
||||
use FireflyIII\Events\Security\MFANewBackupCodes;
|
||||
use FireflyIII\Events\Security\MFAUsedBackupCode;
|
||||
use FireflyIII\Notifications\Security\MFABackupFewLeftNotification;
|
||||
use FireflyIII\Notifications\Security\MFABackupNoLeftNotification;
|
||||
use FireflyIII\Notifications\Security\MFAManyFailedAttemptsNotification;
|
||||
use FireflyIII\Notifications\Security\MFAUsedBackupCodeNotification;
|
||||
use FireflyIII\Notifications\Security\NewBackupCodesNotification;
|
||||
@@ -40,57 +36,6 @@ use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class MFAHandler
|
||||
{
|
||||
public function sendBackupFewLeftMail(MFABackupFewLeft $event): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
$user = $event->user;
|
||||
$count = $event->count;
|
||||
|
||||
try {
|
||||
Notification::send($user, new MFABackupFewLeftNotification($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 sendBackupNoLeftMail(MFABackupNoLeft $event): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
$user = $event->user;
|
||||
|
||||
try {
|
||||
Notification::send($user, new MFABackupNoLeftNotification($user));
|
||||
} 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 sendMFAFailedAttemptsMail(MFAManyFailedAttempts $event): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
@@ -23,13 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Events\Security\MFABackupFewLeft;
|
||||
use FireflyIII\Events\Security\MFABackupNoLeft;
|
||||
use FireflyIII\Events\Security\MFAManyFailedAttempts;
|
||||
use FireflyIII\Events\Security\MFAUsedBackupCode;
|
||||
use FireflyIII\Events\Security\User\UserHasFewMFABackupCodesLeft;
|
||||
use FireflyIII\Events\Security\User\UserHasNoMFABackupCodesLeft;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Contracts\View\View;
|
||||
@@ -49,12 +49,12 @@ class TwoFactorController extends Controller
|
||||
/**
|
||||
* What to do if 2FA lost?
|
||||
*/
|
||||
public function lostTwoFactor(): Factory|View
|
||||
public function lostTwoFactor(): Factory | View
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$siteOwner = config('firefly.site_owner');
|
||||
$title = (string) trans('firefly.two_factor_forgot_title');
|
||||
$title = (string)trans('firefly.two_factor_forgot_title');
|
||||
|
||||
return view('auth.lost-two-factor', ['user' => $user, 'siteOwner' => $siteOwner, 'title' => $title]);
|
||||
}
|
||||
@@ -63,11 +63,11 @@ class TwoFactorController extends Controller
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
public function submitMFA(Request $request): Redirector|RedirectResponse
|
||||
public function submitMFA(Request $request): Redirector | RedirectResponse
|
||||
{
|
||||
/** @var array $mfaHistory */
|
||||
$mfaHistory = Preferences::get('mfa_history', [])->data;
|
||||
$mfaCode = (string) $request->get('one_time_password');
|
||||
$mfaHistory = Preferences::get('mfa_history', [])->data;
|
||||
$mfaCode = (string)$request->get('one_time_password');
|
||||
|
||||
// is in history? then refuse to use it.
|
||||
if ($this->inMFAHistory($mfaCode, $mfaHistory)) {
|
||||
@@ -82,7 +82,7 @@ class TwoFactorController extends Controller
|
||||
|
||||
// if not OK, save error.
|
||||
if (!$authenticator->isAuthenticated()) {
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
$this->addToMFAFailureCounter();
|
||||
$counter = $this->getMFAFailureCounter();
|
||||
if (3 === $counter || 10 === $counter) {
|
||||
@@ -168,7 +168,7 @@ class TwoFactorController extends Controller
|
||||
|
||||
private function addToMFAFailureCounter(): void
|
||||
{
|
||||
$preference = (int) Preferences::get('mfa_failure_count', 0)->data;
|
||||
$preference = (int)Preferences::get('mfa_failure_count', 0)->data;
|
||||
++$preference;
|
||||
Log::channel('audit')->info(sprintf('MFA failure count is set to %d.', $preference));
|
||||
Preferences::set('mfa_failure_count', $preference);
|
||||
@@ -176,7 +176,7 @@ class TwoFactorController extends Controller
|
||||
|
||||
private function getMFAFailureCounter(): int
|
||||
{
|
||||
$value = (int) Preferences::get('mfa_failure_count', 0)->data;
|
||||
$value = (int)Preferences::get('mfa_failure_count', 0)->data;
|
||||
Log::channel('audit')->info(sprintf('MFA failure count is %d.', $value));
|
||||
|
||||
return $value;
|
||||
@@ -220,7 +220,7 @@ class TwoFactorController extends Controller
|
||||
*/
|
||||
private function removeFromBackupCodes(string $mfaCode): void
|
||||
{
|
||||
$list = Preferences::get('mfa_recovery', [])->data;
|
||||
$list = Preferences::get('mfa_recovery', [])->data;
|
||||
if (!is_array($list)) {
|
||||
$list = [];
|
||||
}
|
||||
@@ -230,13 +230,13 @@ class TwoFactorController extends Controller
|
||||
if (count($newList) <= 3 && count($newList) > 0) {
|
||||
$user = auth()->user();
|
||||
Log::channel('audit')->info(sprintf('User "%s" has used a backup code. They have %d backup codes left.', $user->email, count($newList)));
|
||||
event(new MFABackupFewLeft($user, count($newList)));
|
||||
event(new UserHasFewMFABackupCodesLeft($user, count($newList)));
|
||||
}
|
||||
// if the list is empty, send notification
|
||||
if (0 === count($newList)) {
|
||||
$user = auth()->user();
|
||||
Log::channel('audit')->info(sprintf('User "%s" has used their last backup code.', $user->email));
|
||||
event(new MFABackupNoLeft($user));
|
||||
event(new UserHasNoMFABackupCodesLeft($user));
|
||||
}
|
||||
|
||||
Preferences::set('mfa_recovery', $newList);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/*
|
||||
* NotifiesUserAboutFewCodesLeft.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\UserHasFewMFABackupCodesLeft;
|
||||
use FireflyIII\Notifications\Security\MFABackupFewLeftNotification;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutFewCodesLeft
|
||||
{
|
||||
|
||||
public function handle(UserHasFewMFABackupCodesLeft $event): void {
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
$user = $event->user;
|
||||
$count = $event->count;
|
||||
|
||||
try {
|
||||
Notification::send($user, new MFABackupFewLeftNotification($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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/*
|
||||
* NotifiesUserAboutNoCodesLeft.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\UserHasNoMFABackupCodesLeft;
|
||||
use FireflyIII\Notifications\Security\MFABackupNoLeftNotification;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutNoCodesLeft
|
||||
{
|
||||
public function handle(UserHasNoMFABackupCodesLeft $event): void {
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
$user = $event->user;
|
||||
|
||||
try {
|
||||
Notification::send($user, new MFABackupNoLeftNotification($user));
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,8 +35,6 @@ use FireflyIII\Events\RequestedNewPassword;
|
||||
use FireflyIII\Events\RequestedReportOnJournals;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\RequestedVersionCheckStatus;
|
||||
use FireflyIII\Events\Security\MFABackupFewLeft;
|
||||
use FireflyIII\Events\Security\MFABackupNoLeft;
|
||||
use FireflyIII\Events\Security\MFAManyFailedAttempts;
|
||||
use FireflyIII\Events\Security\MFANewBackupCodes;
|
||||
use FireflyIII\Events\Security\MFAUsedBackupCode;
|
||||
@@ -193,12 +191,12 @@ class EventServiceProvider extends ServiceProvider
|
||||
MFAUsedBackupCode::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendUsedBackupCodeMail',
|
||||
],
|
||||
MFABackupFewLeft::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupFewLeftMail',
|
||||
],
|
||||
MFABackupNoLeft::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupNoLeftMail',
|
||||
],
|
||||
// MFABackupFewLeft::class => [
|
||||
// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupFewLeftMail',
|
||||
// ],
|
||||
// MFABackupNoLeft::class => [
|
||||
// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupNoLeftMail',
|
||||
// ],
|
||||
MFAManyFailedAttempts::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAFailedAttemptsMail',
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user