Skip to content

Commit 0b8e7a8

Browse files
authored
Added config option for custom OTP window (#385)
* Added config option for custom OTP window * StyleCI fixes
1 parent 9c67c3f commit 0b8e7a8

File tree

3 files changed

+40
-0
lines changed

3 files changed

+40
-0
lines changed

src/TwoFactorAuthenticationProvider.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ public function qrCodeUrl($companyName, $companyEmail, $secret)
6767
*/
6868
public function verify($secret, $code)
6969
{
70+
if (is_int($customWindow = config('fortify-options.two-factor-authentication.window'))) {
71+
$this->engine->setWindow($customWindow);
72+
}
73+
7074
$timestamp = $this->engine->verifyKeyNewer(
7175
$secret, $code, optional($this->cache)->get($key = 'fortify.2fa_codes.'.md5($code))
7276
);

stubs/fortify.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@
140140
Features::twoFactorAuthentication([
141141
'confirm' => true,
142142
'confirmPassword' => true,
143+
// 'window' => 0,
143144
]),
144145
],
145146

tests/AuthenticatedSessionControllerTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,41 @@ public function test_two_factor_challenge_can_be_passed_via_code()
296296
->assertSessionMissing('login.id');
297297
}
298298

299+
public function test_two_factor_challenge_fails_for_old_otp_and_zero_window()
300+
{
301+
app('config')->set('auth.providers.users.model', TestTwoFactorAuthenticationSessionUser::class);
302+
303+
//Setting window to 0 should mean any old OTP is instantly invalid
304+
app('config')->set('fortify.features', [
305+
Features::twoFactorAuthentication(['window' => 0]),
306+
]);
307+
308+
$this->loadLaravelMigrations(['--database' => 'testbench']);
309+
$this->artisan('migrate', ['--database' => 'testbench'])->run();
310+
311+
$tfaEngine = app(Google2FA::class);
312+
$userSecret = $tfaEngine->generateSecretKey();
313+
$currentTs = $tfaEngine->getTimestamp();
314+
$previousOtp = $tfaEngine->oathTotp($userSecret, $currentTs - 1);
315+
316+
$user = TestTwoFactorAuthenticationSessionUser::forceCreate([
317+
'name' => 'Taylor Otwell',
318+
'email' => '[email protected]',
319+
'password' => bcrypt('secret'),
320+
'two_factor_secret' => encrypt($userSecret),
321+
]);
322+
323+
$response = $this->withSession([
324+
'login.id' => $user->id,
325+
'login.remember' => false,
326+
])->withoutExceptionHandling()->post('/two-factor-challenge', [
327+
'code' => $previousOtp,
328+
]);
329+
330+
$response->assertRedirect('/two-factor-challenge')
331+
->assertSessionHas('login.id');
332+
}
333+
299334
public function test_two_factor_challenge_can_be_passed_via_recovery_code()
300335
{
301336
app('config')->set('auth.providers.users.model', TestTwoFactorAuthenticationSessionUser::class);

0 commit comments

Comments
 (0)