config = m::mock(Repository::class); $this->encrypter = m::mock(Encrypter::class); $this->google2FA = m::mock(Google2FA::class); $this->repository = m::mock(UserRepositoryInterface::class); $this->config->shouldReceive('get')->with('pterodactyl.auth.2fa.window')->once()->andReturn(self::TEST_WINDOW_INT); $this->encrypter->shouldReceive('decrypt')->with(self::USER_TOTP_SECRET)->once()->andReturn(self::DECRYPTED_USER_SECRET); } /** * Test that 2FA can be enabled for a user. */ public function testTwoFactorIsEnabledForUser() { $model = factory(User::class)->make(['totp_secret' => self::USER_TOTP_SECRET, 'use_totp' => false]); $this->google2FA->shouldReceive('verifyKey')->with(self::DECRYPTED_USER_SECRET, 'test-token', self::TEST_WINDOW_INT)->once()->andReturn(true); $this->repository->shouldReceive('withoutFreshModel->update')->with($model->id, [ 'totp_authenticated_at' => Carbon::now(), 'use_totp' => true, ])->once()->andReturnNull(); $this->assertTrue($this->getService()->handle($model, 'test-token')); } /** * Test that 2FA can be disabled for a user. */ public function testTwoFactorIsDisabled() { $model = factory(User::class)->make(['totp_secret' => self::USER_TOTP_SECRET, 'use_totp' => true]); $this->google2FA->shouldReceive('verifyKey')->with(self::DECRYPTED_USER_SECRET, 'test-token', self::TEST_WINDOW_INT)->once()->andReturn(true); $this->repository->shouldReceive('withoutFreshModel->update')->with($model->id, [ 'totp_authenticated_at' => Carbon::now(), 'use_totp' => false, ])->once()->andReturnNull(); $this->assertTrue($this->getService()->handle($model, 'test-token')); } /** * Test that 2FA will remain disabled for a user. */ public function testTwoFactorRemainsDisabledForUser() { $model = factory(User::class)->make(['totp_secret' => self::USER_TOTP_SECRET, 'use_totp' => false]); $this->google2FA->shouldReceive('verifyKey')->with(self::DECRYPTED_USER_SECRET, 'test-token', self::TEST_WINDOW_INT)->once()->andReturn(true); $this->repository->shouldReceive('withoutFreshModel->update')->with($model->id, [ 'totp_authenticated_at' => Carbon::now(), 'use_totp' => false, ])->once()->andReturnNull(); $this->assertTrue($this->getService()->handle($model, 'test-token', false)); } /** * Test that an exception is thrown if the token provided is invalid. * * @expectedException \Pterodactyl\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid */ public function testExceptionIsThrownIfTokenIsInvalid() { $model = factory(User::class)->make(['totp_secret' => self::USER_TOTP_SECRET]); $this->google2FA->shouldReceive('verifyKey')->once()->andReturn(false); $this->getService()->handle($model, 'test-token'); } /** * Return an instance of the service with mocked dependencies. * * @return \Pterodactyl\Services\Users\ToggleTwoFactorService */ private function getService(): ToggleTwoFactorService { return new ToggleTwoFactorService($this->encrypter, $this->google2FA, $this->config, $this->repository); } }