mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
fix(mfa): fix notification on email MFA resend (#18208)
* fix(mfa): fix notification on email MFA resend - Prevent false success notifications when rate limited - Enhance existing tests to verify UI notifications - Modify sendCode() to return bool indicating success/failure - Update resend actions in login, setup, and disable flows - Add English translation keys for rate limited messages * consistency * cs * fix tests --------- Co-authored-by: Dan Harrin <git@danharrin.com>
This commit is contained in:
co-authored by
Dan Harrin
parent
db8d4556ca
commit
e5cf9885f5
@@ -30,6 +30,10 @@ return [
|
||||
'title' => 'We\'ve sent you a new code by email',
|
||||
],
|
||||
|
||||
'throttled' => [
|
||||
'title' => 'Too many resend attempts. Please wait before requesting another code.',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
@@ -30,6 +30,10 @@ return [
|
||||
'title' => 'We\'ve sent you a new code by email',
|
||||
],
|
||||
|
||||
'throttled' => [
|
||||
'title' => 'Too many resend attempts. Please wait before requesting another code.',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
@@ -41,6 +41,10 @@ return [
|
||||
'title' => 'We\'ve sent you a new code by email',
|
||||
],
|
||||
|
||||
'throttled' => [
|
||||
'title' => 'Too many resend attempts. Please wait before requesting another code.',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
+8
-1
@@ -43,7 +43,14 @@ class DisableEmailAuthenticationAction
|
||||
/** @var HasEmailAuthentication $user */
|
||||
$user = Filament::auth()->user();
|
||||
|
||||
$emailAuthentication->sendCode($user);
|
||||
if (! $emailAuthentication->sendCode($user)) {
|
||||
Notification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/disable.modal.form.code.actions.resend.notifications.throttled.title'))
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Notification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/disable.modal.form.code.actions.resend.notifications.resent.title'))
|
||||
|
||||
+8
-1
@@ -44,7 +44,14 @@ class SetUpEmailAuthenticationAction
|
||||
/** @var HasEmailAuthentication $user */
|
||||
$user = Filament::auth()->user();
|
||||
|
||||
$emailAuthentication->sendCode($user);
|
||||
if (! $emailAuthentication->sendCode($user)) {
|
||||
Notification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/set-up.modal.form.code.actions.resend.notifications.throttled.title'))
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Notification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/set-up.modal.form.code.actions.resend.notifications.resent.title'))
|
||||
|
||||
@@ -55,7 +55,7 @@ class EmailAuthentication implements HasBeforeChallengeHook, MultiFactorAuthenti
|
||||
return $user->hasEmailAuthentication();
|
||||
}
|
||||
|
||||
public function sendCode(HasEmailAuthentication $user): void
|
||||
public function sendCode(HasEmailAuthentication $user): bool
|
||||
{
|
||||
if (! ($user instanceof Model)) {
|
||||
throw new LogicException('The [' . $user::class . '] class must be an instance of [' . Model::class . '] to use email authentication.');
|
||||
@@ -70,7 +70,7 @@ class EmailAuthentication implements HasBeforeChallengeHook, MultiFactorAuthenti
|
||||
$rateLimitingKey = "filament_email_authentication.{$user->getKey()}";
|
||||
|
||||
if (RateLimiter::tooManyAttempts($rateLimitingKey, maxAttempts: 2)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
RateLimiter::hit($rateLimitingKey);
|
||||
@@ -85,6 +85,8 @@ class EmailAuthentication implements HasBeforeChallengeHook, MultiFactorAuthenti
|
||||
'code' => $code,
|
||||
'codeExpiryMinutes' => $codeExpiryMinutes,
|
||||
]));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function enableEmailAuthentication(HasEmailAuthentication $user): void
|
||||
@@ -197,7 +199,14 @@ class EmailAuthentication implements HasBeforeChallengeHook, MultiFactorAuthenti
|
||||
->label(__('filament-panels::auth/multi-factor/email/provider.login_form.code.actions.resend.label'))
|
||||
->link()
|
||||
->action(function () use ($user): void {
|
||||
$this->sendCode($user);
|
||||
if (! $this->sendCode($user)) {
|
||||
Notification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/provider.login_form.code.actions.resend.notifications.throttled.title'))
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Notification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/provider.login_form.code.actions.resend.notifications.resent.title'))
|
||||
|
||||
@@ -5,6 +5,7 @@ use Filament\Auth\MultiFactor\Email\EmailAuthentication;
|
||||
use Filament\Auth\MultiFactor\Email\Notifications\VerifyEmailAuthentication;
|
||||
use Filament\Auth\Pages\EditProfile;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Notifications\Notification as FilamentNotification;
|
||||
use Filament\Tests\Fixtures\Models\User;
|
||||
use Filament\Tests\TestCase;
|
||||
use Illuminate\Support\Arr;
|
||||
@@ -70,7 +71,12 @@ it('can resend the code to the user', function (): void {
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent('code'));
|
||||
->schemaComponent('code'))
|
||||
->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/disable.modal.form.code.actions.resend.notifications.resent.title'))
|
||||
->success()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 2);
|
||||
});
|
||||
@@ -86,13 +92,23 @@ it('can resend the code to the user more than twice per minute', function (): vo
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent('code'));
|
||||
->schemaComponent('code'))
|
||||
->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/disable.modal.form.code.actions.resend.notifications.resent.title'))
|
||||
->success()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 2);
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent('code'));
|
||||
->schemaComponent('code'))
|
||||
->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/disable.modal.form.code.actions.resend.notifications.throttled.title'))
|
||||
->danger()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 2);
|
||||
|
||||
@@ -100,7 +116,12 @@ it('can resend the code to the user more than twice per minute', function (): vo
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent('code'));
|
||||
->schemaComponent('code'))
|
||||
->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/disable.modal.form.code.actions.resend.notifications.resent.title'))
|
||||
->success()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 3);
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ use Filament\Auth\MultiFactor\Email\EmailAuthentication;
|
||||
use Filament\Auth\MultiFactor\Email\Notifications\VerifyEmailAuthentication;
|
||||
use Filament\Auth\Pages\Login;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Notifications\Notification as FilamentNotification;
|
||||
use Filament\Tests\Fixtures\Models\User;
|
||||
use Filament\Tests\TestCase;
|
||||
use Illuminate\Support\Arr;
|
||||
@@ -108,8 +109,14 @@ it('can resend the code to the user', function (): void {
|
||||
$this->travelBack();
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent("{$emailAuthentication->getId()}.code", schema: 'multiFactorChallengeForm'));
|
||||
->callAction(
|
||||
TestAction::make('resend')
|
||||
->schemaComponent("{$emailAuthentication->getId()}.code", schema: 'multiFactorChallengeForm')
|
||||
)->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/provider.login_form.code.actions.resend.notifications.resent.title'))
|
||||
->success()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 2);
|
||||
});
|
||||
@@ -133,22 +140,40 @@ it('can not resend the code to the user more than twice per minute', function ()
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 1);
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent("{$emailAuthentication->getId()}.code", schema: 'multiFactorChallengeForm'));
|
||||
->callAction(
|
||||
TestAction::make('resend')
|
||||
->schemaComponent("{$emailAuthentication->getId()}.code", schema: 'multiFactorChallengeForm')
|
||||
)->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/provider.login_form.code.actions.resend.notifications.resent.title'))
|
||||
->success()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 2);
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent("{$emailAuthentication->getId()}.code", schema: 'multiFactorChallengeForm'));
|
||||
->callAction(
|
||||
TestAction::make('resend')
|
||||
->schemaComponent("{$emailAuthentication->getId()}.code", schema: 'multiFactorChallengeForm')
|
||||
)->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/provider.login_form.code.actions.resend.notifications.throttled.title'))
|
||||
->danger()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 2);
|
||||
|
||||
$this->travelBack();
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent("{$emailAuthentication->getId()}.code", schema: 'multiFactorChallengeForm'));
|
||||
->callAction(
|
||||
TestAction::make('resend')
|
||||
->schemaComponent("{$emailAuthentication->getId()}.code", schema: 'multiFactorChallengeForm')
|
||||
)->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/provider.login_form.code.actions.resend.notifications.resent.title'))
|
||||
->success()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 3);
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ use Filament\Auth\MultiFactor\Email\EmailAuthentication;
|
||||
use Filament\Auth\MultiFactor\Email\Notifications\VerifyEmailAuthentication;
|
||||
use Filament\Auth\Pages\EditProfile;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Notifications\Notification as FilamentNotification;
|
||||
use Filament\Tests\Fixtures\Models\User;
|
||||
use Filament\Tests\TestCase;
|
||||
use Illuminate\Support\Arr;
|
||||
@@ -81,7 +82,12 @@ it('can resend the code to the user', function (): void {
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent('code'));
|
||||
->schemaComponent('code'))
|
||||
->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/set-up.modal.form.code.actions.resend.notifications.resent.title'))
|
||||
->success()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 2);
|
||||
});
|
||||
@@ -97,13 +103,23 @@ it('can resend the code to the user more than twice per minute', function (): vo
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent('code'));
|
||||
->schemaComponent('code'))
|
||||
->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/set-up.modal.form.code.actions.resend.notifications.resent.title'))
|
||||
->success()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 2);
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent('code'));
|
||||
->schemaComponent('code'))
|
||||
->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/set-up.modal.form.code.actions.resend.notifications.throttled.title'))
|
||||
->danger()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 2);
|
||||
|
||||
@@ -111,7 +127,12 @@ it('can resend the code to the user more than twice per minute', function (): vo
|
||||
|
||||
$livewire
|
||||
->callAction(TestAction::make('resend')
|
||||
->schemaComponent('code'));
|
||||
->schemaComponent('code'))
|
||||
->assertNotified(
|
||||
FilamentNotification::make()
|
||||
->title(__('filament-panels::auth/multi-factor/email/actions/set-up.modal.form.code.actions.resend.notifications.resent.title'))
|
||||
->success()
|
||||
);
|
||||
|
||||
Notification::assertSentTimes(VerifyEmailAuthentication::class, 3);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user