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 19:18:17 +00:00
committed by GitHub
8 changed files with 170 additions and 116 deletions

View File

@@ -1,8 +1,7 @@
<?php
/*
* UnknownUserAttemptedLogin.php
* Copyright (c) 2024 james@firefly-iii.org.
* UnknownUserTriedLogin.php
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -17,16 +16,14 @@
* 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\System;
use Illuminate\Queue\SerializesModels;
class UnknownUserAttemptedLogin
class UnknownUserTriedLogin
{
use SerializesModels;

View File

@@ -1,8 +1,7 @@
<?php
/*
* UserAttemptedLogin.php
* Copyright (c) 2024 james@firefly-iii.org.
* UserFailedLoginAttempt.php
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -17,19 +16,19 @@
* 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 Carbon\Exceptions\InvalidFormatException;
use FireflyIII\Events\Event;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Queue\SerializesModels;
use InvalidArgumentException;
class UserAttemptedLogin extends Event
class UserFailedLoginAttempt extends Event
{
use SerializesModels;
@@ -39,6 +38,9 @@ class UserAttemptedLogin extends Event
{
if ($user instanceof User) {
$this->user = $user;
return;
}
throw new InvalidArgumentException('User must be an instance of User.');
}
}

View File

@@ -26,18 +26,16 @@ namespace FireflyIII\Handlers\Events;
use Exception;
use FireflyIII\Events\Admin\InvitationCreated;
use FireflyIII\Events\NewVersionAvailable;
use FireflyIII\Events\Security\UnknownUserAttemptedLogin;
use FireflyIII\Events\Test\OwnerTestNotificationChannel;
use FireflyIII\Notifications\Admin\UnknownUserLoginAttempt;
use FireflyIII\Notifications\Admin\UserInvitation;
use FireflyIII\Notifications\Admin\VersionCheckResult;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Notifications\Test\OwnerTestNotificationEmail;
use FireflyIII\Notifications\Test\OwnerTestNotificationPushover;
use FireflyIII\Notifications\Test\OwnerTestNotificationSlack;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use FireflyIII\Support\Facades\FireflyConfig;
/**
* Class AdminEventHandler.
@@ -70,27 +68,6 @@ class AdminEventHandler
}
}
public function sendLoginAttemptNotification(UnknownUserAttemptedLogin $event): void
{
try {
$owner = new OwnerNotifiable();
Notification::send($owner, new UnknownUserLoginAttempt($event->address));
} 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());
}
}
/**
* Send new version message to admin.
@@ -140,10 +117,10 @@ class AdminEventHandler
break;
// case 'ntfy':
// $class = OwnerTestNotificationNtfy::class;
//
// break;
// case 'ntfy':
// $class = OwnerTestNotificationNtfy::class;
//
// break;
case 'pushover':
$class = OwnerTestNotificationPushover::class;

View File

@@ -32,7 +32,6 @@ use FireflyIII\Events\Admin\InvitationCreated;
use FireflyIII\Events\DetectedNewIPAddress;
use FireflyIII\Events\RegisteredUser;
use FireflyIII\Events\RequestedNewPassword;
use FireflyIII\Events\Security\UserAttemptedLogin;
use FireflyIII\Events\Test\UserTestNotificationChannel;
use FireflyIII\Events\UserChangedEmail;
use FireflyIII\Exceptions\FireflyException;
@@ -43,7 +42,6 @@ use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup;
use FireflyIII\Models\UserRole;
use FireflyIII\Notifications\Admin\UserRegistration as AdminRegistrationNotification;
use FireflyIII\Notifications\Security\UserFailedLoginAttempt;
use FireflyIII\Notifications\Test\UserTestNotificationEmail;
use FireflyIII\Notifications\Test\UserTestNotificationPushover;
use FireflyIII\Notifications\Test\UserTestNotificationSlack;
@@ -51,13 +49,13 @@ use FireflyIII\Notifications\User\UserLogin;
use FireflyIII\Notifications\User\UserNewPassword;
use FireflyIII\Notifications\User\UserRegistration as UserRegistrationNotification;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Auth\Events\Login;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use FireflyIII\Support\Facades\FireflyConfig;
/**
* Class UserEventHandler.
@@ -92,8 +90,8 @@ class UserEventHandler
$repository = app(UserRepositoryInterface::class);
/** @var User $user */
$user = $event->user;
$count = $repository->count();
$user = $event->user;
$count = $repository->count();
// only act when there is 1 user in the system and he has no admin rights.
if (1 === $count && !$repository->hasRole($user, 'owner')) {
@@ -125,13 +123,13 @@ class UserEventHandler
*/
public function createGroupMembership(RegisteredUser $event): void
{
$user = $event->user;
$groupExists = true;
$groupTitle = $user->email;
$index = 1;
$user = $event->user;
$groupExists = true;
$groupTitle = $user->email;
$index = 1;
/** @var null|UserGroup $group */
$group = null;
$group = null;
// create a new group.
while ($groupExists) { // @phpstan-ignore-line
@@ -141,7 +139,7 @@ class UserEventHandler
break;
}
$groupTitle = sprintf('%s-%d', $user->email, $index);
$groupTitle = sprintf('%s-%d', $user->email, $index);
++$index;
if ($index > 99) {
throw new FireflyException('Email address can no longer be used for registrations.');
@@ -149,7 +147,7 @@ class UserEventHandler
}
/** @var null|UserRole $role */
$role = UserRole::where('title', UserRoleEnum::OWNER->value)->first();
$role = UserRole::where('title', UserRoleEnum::OWNER->value)->first();
if (null === $role) {
throw new FireflyException('The user role is unexpectedly empty. Did you run all migrations?');
}
@@ -173,7 +171,7 @@ class UserEventHandler
$repository = app(UserRepositoryInterface::class);
/** @var User $user */
$user = $event->user;
$user = $event->user;
if ($repository->hasRole($user, 'demo')) {
// set user back to English.
Preferences::setForUser($user, 'language', 'en_US');
@@ -298,26 +296,6 @@ class UserEventHandler
}
}
public function sendLoginAttemptNotification(UserAttemptedLogin $event): void
{
try {
Notification::send($event->user, new UserFailedLoginAttempt($event->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());
}
}
/**
* Send a new password to the user.
@@ -408,10 +386,10 @@ class UserEventHandler
break;
// case 'ntfy':
// $class = UserTestNotificationNtfy::class;
//
// break;
// case 'ntfy':
// $class = UserTestNotificationNtfy::class;
//
// break;
case 'pushover':
$class = UserTestNotificationPushover::class;
@@ -448,7 +426,7 @@ class UserEventHandler
public function storeUserIPAddress(ActuallyLoggedIn $event): void
{
Log::debug('Now in storeUserIPAddress');
$user = $event->user;
$user = $event->user;
if ($user->hasRole('demo')) {
Log::debug('Do not log demo user logins');
@@ -465,8 +443,8 @@ class UserEventHandler
return;
}
$inArray = false;
$ip = request()->ip();
$inArray = false;
$ip = request()->ip();
Log::debug(sprintf('User logging in from IP address %s', $ip));
// update array if in array
@@ -494,7 +472,7 @@ class UserEventHandler
$preference = array_values($preference);
/** @var bool $send */
$send = Preferences::getForUser($user, 'notification_user_login', true)->data;
$send = Preferences::getForUser($user, 'notification_user_login', true)->data;
Preferences::setForUser($user, 'login_ip_history', $preference);
if (false === $inArray && true === $send) {

View File

@@ -25,12 +25,13 @@ namespace FireflyIII\Http\Controllers\Auth;
use Carbon\Carbon;
use FireflyIII\Events\ActuallyLoggedIn;
use FireflyIII\Events\Security\UnknownUserAttemptedLogin;
use FireflyIII\Events\Security\UserAttemptedLogin;
use FireflyIII\Events\Security\System\UnknownUserTriedLogin;
use FireflyIII\Events\Security\User\UserFailedLoginAttempt;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Providers\RouteServiceProvider;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Contracts\Foundation\Application;
@@ -50,7 +51,6 @@ use Illuminate\Validation\ValidationException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\HttpFoundation\Response as ResponseAlias;
use FireflyIII\Support\Facades\FireflyConfig;
/**
* Class LoginController
@@ -70,7 +70,7 @@ class LoginController extends Controller
protected string $redirectTo = RouteServiceProvider::HOME;
private UserRepositoryInterface $repository;
private string $username = 'email';
private string $username = 'email';
/**
* Create a new controller instance.
@@ -87,7 +87,7 @@ class LoginController extends Controller
*
* @throws ValidationException
*/
public function login(Request $request): JsonResponse|RedirectResponse
public function login(Request $request): JsonResponse | RedirectResponse
{
$username = $request->get($this->username());
Log::channel('audit')->info(sprintf('User is trying to login using "%s"', $username));
@@ -105,8 +105,7 @@ class LoginController extends Controller
$this->username => trans('auth.failed'),
]
)
->onlyInput($this->username)
;
->onlyInput($this->username);
}
Log::debug('Login data is present.');
@@ -138,10 +137,10 @@ class LoginController extends Controller
$user = $this->repository->findByEmail($username);
if (!$user instanceof User) {
// send event to owner.
event(new UnknownUserAttemptedLogin($username));
event(new UnknownUserTriedLogin($username));
}
if ($user instanceof User) {
event(new UserAttemptedLogin($user));
event(new UserFailedLoginAttempt($user));
}
// Copied directly from AuthenticatesUsers, but with logging added:
@@ -187,10 +186,10 @@ class LoginController extends Controller
/**
* Log the user out of the application.
*/
public function logout(Request $request): Redirector|RedirectResponse|Response
public function logout(Request $request): Redirector | RedirectResponse | Response
{
$authGuard = config('firefly.authentication_guard');
$logoutUrl = config('firefly.custom_logout_url');
$authGuard = config('firefly.authentication_guard');
$logoutUrl = config('firefly.custom_logout_url');
if ('remote_user_guard' === $authGuard && '' !== $logoutUrl) {
return redirect($logoutUrl);
}
@@ -224,13 +223,13 @@ class LoginController extends Controller
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function showLoginForm(Request $request): Factory|Redirector|RedirectResponse|View
public function showLoginForm(Request $request): Factory | Redirector | RedirectResponse | View
{
Log::channel('audit')->info('Show login form (1.1).');
$count = DB::table('users')->count();
$guard = config('auth.defaults.guard');
$title = (string)trans('firefly.login_page_title');
$count = DB::table('users')->count();
$guard = config('auth.defaults.guard');
$title = (string)trans('firefly.login_page_title');
if (0 === $count && 'web' === $guard) {
return redirect(route('register'));
@@ -250,15 +249,15 @@ class LoginController extends Controller
$allowReset = false;
}
$email = $request->old('email');
$remember = $request->old('remember');
$email = $request->old('email');
$remember = $request->old('remember');
$storeInCookie = config('google2fa.store_in_cookie', false);
$storeInCookie = config('google2fa.store_in_cookie', false);
if (false !== $storeInCookie) {
$cookieName = config('google2fa.cookie_name', 'google2fa_token');
Cookie::queue(Cookie::make($cookieName, 'invalid-'.Carbon::now()->getTimestamp()));
Cookie::queue(Cookie::make($cookieName, 'invalid-' . Carbon::now()->getTimestamp()));
}
$usernameField = $this->username();
$usernameField = $this->username();
return view('auth.login', ['allowRegistration' => $allowRegistration, 'email' => $email, 'remember' => $remember, 'allowReset' => $allowReset, 'title' => $title, 'usernameField' => $usernameField]);
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* NotifiesOwnerAboutUnknownUser.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\System;
use Exception;
use FireflyIII\Events\Security\System\UnknownUserTriedLogin;
use FireflyIII\Notifications\Admin\UnknownUserLoginAttempt;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
class NotifiesOwnerAboutUnknownUser
{
public function handle(UnknownUserTriedLogin $event): void {
try {
$owner = new OwnerNotifiable();
Notification::send($owner, new UnknownUserLoginAttempt($event->address));
} 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());
}
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*
* NotifiesUserAboutFailedLogin.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\UserFailedLoginAttempt;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
class NotifiesUserAboutFailedLogin
{
public function handle(UserFailedLoginAttempt $event): void {
try {
Notification::send($event->user, new \FireflyIII\Notifications\Security\UserFailedLoginAttempt($event->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());
}
}
}

View File

@@ -35,10 +35,6 @@ use FireflyIII\Events\RequestedNewPassword;
use FireflyIII\Events\RequestedReportOnJournals;
use FireflyIII\Events\RequestedSendWebhookMessages;
use FireflyIII\Events\RequestedVersionCheckStatus;
use FireflyIII\Events\Security\MFAManyFailedAttempts;
use FireflyIII\Events\Security\MFANewBackupCodes;
use FireflyIII\Events\Security\UnknownUserAttemptedLogin;
use FireflyIII\Events\Security\UserAttemptedLogin;
use FireflyIII\Events\StoredAccount;
use FireflyIII\Events\StoredTransactionGroup;
use FireflyIII\Events\Test\OwnerTestNotificationChannel;
@@ -69,9 +65,9 @@ class EventServiceProvider extends ServiceProvider
'FireflyIII\Handlers\Events\UserEventHandler@createGroupMembership',
'FireflyIII\Handlers\Events\UserEventHandler@createExchangeRates',
],
UserAttemptedLogin::class => [
'FireflyIII\Handlers\Events\UserEventHandler@sendLoginAttemptNotification',
],
// UserAttemptedLogin::class => [
// 'FireflyIII\Handlers\Events\UserEventHandler@sendLoginAttemptNotification',
// ],
// is a User related event.
Login::class => [
'FireflyIII\Handlers\Events\UserEventHandler@checkSingleUserIsAdmin',
@@ -113,9 +109,9 @@ class EventServiceProvider extends ServiceProvider
'FireflyIII\Handlers\Events\AdminEventHandler@sendInvitationNotification',
'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationInvite',
],
UnknownUserAttemptedLogin::class => [
'FireflyIII\Handlers\Events\AdminEventHandler@sendLoginAttemptNotification',
],
// UnknownUserAttemptedLogin::class => [
// 'FireflyIII\Handlers\Events\AdminEventHandler@sendLoginAttemptNotification',
// ],
// is a Transaction Journal related event.
StoredTransactionGroup::class => [