'array']); $engine = new Google2FA; $secret = $engine->generateSecretKey(); User::factory()->create(['id' => 18, 'email' => 'investor-mfa-qa@example.invalid', 'two_factor_secret' => encrypt($secret), 'two_factor_confirmed_at' => now()]); $code = $engine->getCurrentOtp($secret); $request = Request::create('/two-factor-challenge', 'POST', ['code' => $code]); $session = new Store('qa_trace_unit', new ArraySessionHandler(120)); $session->start(); $session->put('login.id', 18); $request->setLaravelSession($session); $request->attributes->set('qa_auth_trace', 'unit'); $trace = new \PortalQaSessionTrace; $trace->handle($request, fn () => new Response('controlled')); $first = $request->attributes->get('qa_mfa_input_check'); $this->assertTrue($first['secret_decrypts']); $this->assertTrue($first['matches_configured_time_window']); $this->assertFalse($first['previously_used_in_cache']); $this->assertTrue($first['accepted_by_replay_check']); $this->assertFalse(auth()->check()); // Fortify must still accept the unused code: the diagnostic cannot consume it. $this->assertTrue(app(TwoFactorAuthenticationProvider::class)->verify($secret, $code)); $trace->handle($request, fn () => new Response('controlled')); $second = $request->attributes->get('qa_mfa_input_check'); $this->assertTrue($second['matches_configured_time_window']); $this->assertTrue($second['previously_used_in_cache']); $this->assertFalse($second['accepted_by_replay_check']); $this->assertFalse(auth()->check()); $encoded = json_encode($second, JSON_THROW_ON_ERROR); foreach ([$secret, $code, md5($code)] as $value) { $this->assertStringNotContainsString($value, $encoded); } $this->assertSame(18, $session->get('login.id')); } }