fix: prevent duplicate 2FA challenge submissions causing HTTP 419

This commit is contained in:
Paulo Matos 2026-08-12 16:19:54 -03:00
parent 0764ec425d
commit 953726f847
2 changed files with 51 additions and 2 deletions

View file

@ -2,8 +2,18 @@
<x-auth.shell title="Coolify" description="Verify your identity to finish signing in.">
<div class="flex flex-col gap-4" x-data="{
showRecovery: false,
submitting: false,
digits: ['', '', '', '', '', ''],
code: '',
handleSubmit(event) {
if (this.submitting) {
event.preventDefault();
return;
}
this.submitting = true;
},
focusNext(event) {
const nextInput = event.target.nextElementSibling;
if (nextInput?.tagName === 'INPUT') nextInput.focus();
@ -52,7 +62,8 @@
<p x-show="showRecovery" x-cloak>Enter one of the recovery codes you saved when setting up two-factor authentication.</p>
</div>
<form x-ref="challengeForm" action="/two-factor-challenge" method="POST" class="flex flex-col gap-4">
<form x-ref="challengeForm" action="/two-factor-challenge" method="POST" class="flex flex-col gap-4"
@submit="handleSubmit($event)">
@csrf
<div x-show="!showRecovery" class="flex flex-col gap-3">
@ -82,7 +93,7 @@ class="h-12 w-11 rounded-md border border-neutral-300 bg-white text-center text-
</button>
</div>
<x-forms.button class="w-full justify-center" type="submit" isHighlighted>
<x-forms.button class="w-full justify-center" type="submit" x-bind:disabled="submitting" isHighlighted>
Verify and continue
</x-forms.button>
</form>

View file

@ -4,6 +4,7 @@
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Laravel\Fortify\Fortify;
uses(RefreshDatabase::class);
@ -69,6 +70,43 @@
->screenshot(filename: 'login-invalid-credentials');
});
it('prevents Enter from duplicating the automatic two factor challenge submission', function () {
config(['app.maintenance.driver' => 'file']);
$user = createRootUser();
$user->forceFill([
'two_factor_secret' => Fortify::currentEncrypter()->encrypt('JBSWY3DPEHPK3PXP'),
'two_factor_confirmed_at' => now(),
])->save();
$page = visit('/login')
->fill('email', 'test@example.com')
->fill('password', 'password')
->click('Login')
->assertPathIs('/two-factor-challenge');
$page->script(<<<'JS'
window.acceptedTwoFactorSubmissions = 0;
document.querySelector('form[action="/two-factor-challenge"]').addEventListener('submit', (event) => {
if (!event.defaultPrevented) {
window.acceptedTwoFactorSubmissions++;
}
event.preventDefault();
});
JS);
foreach (str_split('123456') as $index => $digit) {
$page->keys(sprintf('[aria-label="Digit %d"]', $index + 1), $digit);
}
$page->keys('[aria-label="Digit 6"]', 'Enter')
->assertScript('window.acceptedTwoFactorSubmissions', 1)
->assertNoJavaScriptErrors()
->screenshot(filename: 'login-two-factor-enter-single-submission');
});
/**
* Create the root user (id 0) with known credentials for browser login tests.
*/