mirror of
https://github.com/Bubka/2FAuth.git
synced 2024-11-26 02:04:52 +01:00
Reorganize and enhance tests
This commit is contained in:
parent
eea7cec043
commit
45b835bbd5
@ -208,7 +208,9 @@ public function withdraw($ids) : void
|
||||
|
||||
Log::info(sprintf('TwoFAccounts #%s withdrawn', implode(',#', $ids)));
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
else Log::info('No TwoFAccount to withdraw');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
|
||||
@ -289,8 +291,13 @@ private function mapArrayToDto($array) : TwoFAccountDto
|
||||
{
|
||||
$dto = new TwoFAccountDto();
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
$dto->$key = ! Arr::has($array, $key) ?: $value;
|
||||
try {
|
||||
foreach ($array as $key => $value) {
|
||||
$dto->$key = ! Arr::has($array, $key) ?: $value;
|
||||
}
|
||||
}
|
||||
catch (\TypeError $ex) {
|
||||
throw new InvalidOtpParameterException($ex->getMessage());
|
||||
}
|
||||
|
||||
return $dto;
|
||||
@ -457,8 +464,10 @@ private function storeTokenImageAsIcon()
|
||||
Log::info(sprintf('Icon file %s stored', $newFilename));
|
||||
}
|
||||
else {
|
||||
// @codeCoverageIgnoreStart
|
||||
Storage::delete($imageFile);
|
||||
throw new \Exception;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $newFilename;
|
||||
|
@ -69,6 +69,10 @@
|
||||
],
|
||||
"test" : [
|
||||
"vendor/bin/phpunit"
|
||||
],
|
||||
"test-coverage-html" : [
|
||||
"@putenv XDEBUG_MODE=coverage",
|
||||
"vendor/bin/phpunit --coverage-html tests/Coverage/"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,9 @@
|
||||
<testsuite name="Feature">
|
||||
<directory suffix="Test.php">./tests/Feature</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Api.v1">
|
||||
<directory suffix="Test.php">./tests/Api/v1</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<server name="APP_ENV" value="testing"/>
|
||||
|
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Auth\Notifications\ResetPassword;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
class ForgotPasswordControllerTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
* @var \App\User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_submit_email_password_request_without_email_returns_validation_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/v1/user/password/lost', [
|
||||
'email' => ''
|
||||
]);
|
||||
|
||||
$response->assertStatus(422)
|
||||
->assertJsonValidationErrors(['email']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_submit_email_password_request_with_invalid_email_returns_validation_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/v1/user/password/lost', [
|
||||
'email' => 'nametest.com'
|
||||
]);
|
||||
|
||||
$response->assertStatus(422)
|
||||
->assertJsonValidationErrors(['email']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_submit_email_password_request_with_unknown_email_returns_validation_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/v1/user/password/lost', [
|
||||
'email' => 'name@test.com'
|
||||
]);
|
||||
|
||||
$response->assertStatus(422)
|
||||
->assertJsonValidationErrors(['email']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_submit_email_password_request_returns_success()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
|
||||
$response = $this->json('POST', '/api/v1/user/password/lost', [
|
||||
'email' => $this->user->email
|
||||
]);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$token = \Illuminate\Support\Facades\DB::table('password_resets')->first();
|
||||
$this->assertNotNull($token);
|
||||
|
||||
Notification::assertSentTo($this->user, ResetPassword::class, function ($notification, $channels) use ($token) {
|
||||
return Hash::check($notification->token, $token->token) === true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_submit_email_password_request__in_demo_mode_returns_unauthorized()
|
||||
{
|
||||
Config::set('2fauth.config.isDemoApp', true);
|
||||
|
||||
$response = $this->json('POST', '/api/v1/user/password/lost', [
|
||||
'email' => ''
|
||||
]);
|
||||
|
||||
$response->assertStatus(401);
|
||||
}
|
||||
|
||||
}
|
81
tests/Api/v1/Controllers/Auth/PasswordControllerTest.php
Normal file
81
tests/Api/v1/Controllers/Auth/PasswordControllerTest.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Api\v1\Controllers\Auth;
|
||||
|
||||
use App\User;
|
||||
use App\Group;
|
||||
use Tests\FeatureTestCase;
|
||||
use App\TwoFAccount;
|
||||
|
||||
class PasswordControllerTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
* @var \App\User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
private const PASSWORD = 'password';
|
||||
private const NEW_PASSWORD = 'newPassword';
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_return_success()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/v1/user/password', [
|
||||
'currentPassword' => self::PASSWORD,
|
||||
'password' => self::NEW_PASSWORD,
|
||||
'password_confirmation' => self::NEW_PASSWORD,
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonStructure([
|
||||
'message',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_passing_bad_current_pwd_return_bad_request()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/v1/user/password', [
|
||||
'currentPassword' => self::NEW_PASSWORD,
|
||||
'password' => self::NEW_PASSWORD,
|
||||
'password_confirmation' => self::NEW_PASSWORD,
|
||||
])
|
||||
->assertStatus(400)
|
||||
->assertJsonStructure([
|
||||
'message',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_passing_invalid_data_return_validation_error()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/v1/user/password', [
|
||||
'currentPassword' => self::PASSWORD,
|
||||
'password' => null,
|
||||
'password_confirmation' => self::NEW_PASSWORD,
|
||||
])
|
||||
->assertStatus(422);
|
||||
}
|
||||
|
||||
}
|
59
tests/Api/v1/Controllers/Auth/RegisterControllerTest.php
Normal file
59
tests/Api/v1/Controllers/Auth/RegisterControllerTest.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Api\v1\Controllers\Auth;
|
||||
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
class RegisterControllerTest extends FeatureTestCase
|
||||
{
|
||||
private const USERNAME = 'john doe';
|
||||
private const EMAIL = 'johndoe@example.org';
|
||||
private const PASSWORD = 'password';
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_register_returns_success()
|
||||
{
|
||||
$response = $this->json('POST', '/api/v1/user', [
|
||||
'name' => self::USERNAME,
|
||||
'email' => self::EMAIL,
|
||||
'password' => self::PASSWORD,
|
||||
'password_confirmation' => self::PASSWORD,
|
||||
])
|
||||
->assertCreated()
|
||||
->assertJsonStructure([
|
||||
'message',
|
||||
'name',
|
||||
])
|
||||
->assertJsonFragment([
|
||||
'name' => self::USERNAME,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_register_with_invalid_data_returns_validation_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/v1/user', [
|
||||
'name' => null,
|
||||
'email' => self::EMAIL,
|
||||
'password' => self::PASSWORD,
|
||||
'password_confirmation' => self::PASSWORD,
|
||||
])
|
||||
->assertStatus(422);
|
||||
}
|
||||
|
||||
}
|
@ -6,21 +6,22 @@
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
class ResetPasswordTest extends TestCase
|
||||
class ResetPasswordControllerTest extends FeatureTestCase
|
||||
{
|
||||
/** @var \App\User */
|
||||
/**
|
||||
* @var \App\User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
|
||||
/**
|
||||
* Testing submitting the reset password without
|
||||
* email address.
|
||||
* @test
|
||||
*/
|
||||
public function testSubmitResetPasswordWithoutInput()
|
||||
public function test_submit_reset_password_without_input_returns_validation_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/password/reset', [
|
||||
$response = $this->json('POST', '/api/v1/user/password/reset', [
|
||||
'email' => '',
|
||||
'password' => '',
|
||||
'password_confirmation' => '',
|
||||
@ -32,12 +33,11 @@ public function testSubmitResetPasswordWithoutInput()
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing submitting the reset password with
|
||||
* invalid input.
|
||||
* @test
|
||||
*/
|
||||
public function testSubmitResetPasswordWithInvalidInput()
|
||||
public function test_submit_reset_password_with_invalid_data_returns_validation_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/password/reset', [
|
||||
$response = $this->json('POST', '/api/v1/user/password/reset', [
|
||||
'email' => 'qsdqsdqsd',
|
||||
'password' => 'foofoofoo',
|
||||
'password_confirmation' => 'barbarbar',
|
||||
@ -49,12 +49,11 @@ public function testSubmitResetPasswordWithInvalidInput()
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing submitting the reset password with
|
||||
* invalid input.
|
||||
* @test
|
||||
*/
|
||||
public function testSubmitResetPasswordWithTooShortPasswords()
|
||||
public function test_submit_reset_password_with_too_short_pwd_returns_validation_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/password/reset', [
|
||||
$response = $this->json('POST', '/api/v1/user/password/reset', [
|
||||
'email' => 'foo@bar.com',
|
||||
'password' => 'foo',
|
||||
'password_confirmation' => 'foo',
|
||||
@ -66,23 +65,16 @@ public function testSubmitResetPasswordWithTooShortPasswords()
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing submitting the rest password.
|
||||
* @test
|
||||
*/
|
||||
public function testSubmitResetPassword()
|
||||
public function test_submit_reset_password_returns_success()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$this->user = factory(User::class)->create([
|
||||
'name' => 'user',
|
||||
'email' => 'user@example.org',
|
||||
'password' => bcrypt('password'),
|
||||
'email_verified_at' => now(),
|
||||
'remember_token' => \Illuminate\Support\Str::random(10)
|
||||
]);
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
$token = Password::broker()->createToken($this->user);
|
||||
|
||||
$response = $this->json('POST', '/api/password/reset', [
|
||||
$response = $this->json('POST', '/api/v1/user/password/reset', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'newpassword',
|
||||
'password_confirmation' => 'newpassword',
|
||||
@ -91,7 +83,7 @@ public function testSubmitResetPassword()
|
||||
|
||||
$this->user->refresh();
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertOk();
|
||||
$this->assertTrue(Hash::check('newpassword', $this->user->password));
|
||||
|
||||
}
|
144
tests/Api/v1/Controllers/Auth/UserControllerTest.php
Normal file
144
tests/Api/v1/Controllers/Auth/UserControllerTest.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Api\v1\Controllers\Auth;
|
||||
|
||||
use App\User;
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
class UserControllerTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
* @var \App\User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
private const NEW_USERNAME = 'Jane DOE';
|
||||
private const NEW_EMAIL = 'janedoe@example.org';
|
||||
private const PASSWORD = 'password';
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_show_existing_user_when_authenticated_returns_success()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/v1/user')
|
||||
->assertOk()
|
||||
->assertExactJson([
|
||||
'name' => $this->user->name,
|
||||
'email' => $this->user->email,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_show_existing_user_when_anonymous_returns_success()
|
||||
{
|
||||
$response = $this->json('GET', '/api/v1/user/name')
|
||||
->assertOk()
|
||||
->assertExactJson([
|
||||
'name' => $this->user->name,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_show_missing_user_returns_success_with_null_name()
|
||||
{
|
||||
User::destroy($this->user->id);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/v1/user')
|
||||
->assertOk()
|
||||
->assertExactJson([
|
||||
'name' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_user_returns_success()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PUT', '/api/v1/user', [
|
||||
'name' => self::NEW_USERNAME,
|
||||
'email' => self::NEW_EMAIL,
|
||||
'password' => self::PASSWORD,
|
||||
])
|
||||
->assertOk()
|
||||
->assertExactJson([
|
||||
'name' => self::NEW_USERNAME,
|
||||
'email' => self::NEW_EMAIL,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_user_in_demo_mode_returns_unchanged_user()
|
||||
{
|
||||
$settingService = resolve('App\Services\SettingServiceInterface');
|
||||
$settingService->set('isDemoApp', true);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PUT', '/api/v1/user', [
|
||||
'name' => self::NEW_USERNAME,
|
||||
'email' => self::NEW_EMAIL,
|
||||
'password' => self::PASSWORD,
|
||||
])
|
||||
->assertOk()
|
||||
->assertExactJson([
|
||||
'name' => $this->user->name,
|
||||
'email' => $this->user->email,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_user_passing_wrong_password_returns_bad_request()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PUT', '/api/v1/user', [
|
||||
'name' => self::NEW_USERNAME,
|
||||
'email' => self::NEW_EMAIL,
|
||||
'password' => 'wrongPassword',
|
||||
])
|
||||
->assertStatus(400);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_user_with_invalid_data_returns_validation_error()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PUT', '/api/v1/user', [
|
||||
'name' => '',
|
||||
'email' => '',
|
||||
'password' => self::PASSWORD,
|
||||
])
|
||||
->assertStatus(422);
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,10 @@
|
||||
use Tests\FeatureTestCase;
|
||||
use App\TwoFAccount;
|
||||
|
||||
|
||||
/**
|
||||
* @covers \App\Api\v1\Controllers\GroupController
|
||||
*/
|
||||
class GroupControllerTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
|
@ -6,6 +6,10 @@
|
||||
use Illuminate\Foundation\Testing\WithoutMiddleware;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
||||
/**
|
||||
* @covers \App\Api\v1\Controllers\IconController
|
||||
*/
|
||||
class IconControllerTest extends TestCase
|
||||
{
|
||||
|
||||
|
@ -7,7 +7,11 @@
|
||||
use App\TwoFAccount;
|
||||
use Tests\Classes\LocalFile;
|
||||
|
||||
class QrcodeControllerTest extends FeatureTestCase
|
||||
|
||||
/**
|
||||
* @covers \App\Api\v1\Controllers\QrCodeController
|
||||
*/
|
||||
class QrCodeControllerTest extends FeatureTestCase
|
||||
{
|
||||
|
||||
/**
|
@ -7,6 +7,10 @@
|
||||
use Tests\FeatureTestCase;
|
||||
use App\TwoFAccount;
|
||||
|
||||
|
||||
/**
|
||||
* @covers \App\Api\v1\Controllers\SettingController
|
||||
*/
|
||||
class SettingControllerTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
|
@ -3,11 +3,16 @@
|
||||
namespace Tests\Api\v1\Unit;
|
||||
|
||||
use App\User;
|
||||
use App\Group;
|
||||
use Tests\FeatureTestCase;
|
||||
use App\TwoFAccount;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
|
||||
/**
|
||||
* @covers \App\Api\v1\Controllers\TwoFAccountController
|
||||
*/
|
||||
class TwoFAccountControllerTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
@ -15,6 +20,11 @@ class TwoFAccountControllerTest extends FeatureTestCase
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @var \App\Group
|
||||
*/
|
||||
protected $group;
|
||||
|
||||
private const ACCOUNT = 'account';
|
||||
private const SERVICE = 'service';
|
||||
private const SECRET = 'A4GRFHVVRBGY7UIW';
|
||||
@ -156,6 +166,7 @@ public function setUp(): void
|
||||
parent::setUp();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
$this->group = factory(Group::class)->create();
|
||||
}
|
||||
|
||||
|
||||
@ -419,6 +430,87 @@ public function test_store_with_invalid_uri_returns_validation_error()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_store_assigns_created_account_when_default_group_is_a_specific_one()
|
||||
{
|
||||
// Set the default group to a specific one
|
||||
$settingService = resolve('App\Services\SettingServiceInterface');
|
||||
$settingService->set('defaultGroup', $this->group->id);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/v1/twofaccounts', [
|
||||
'uri' => self::TOTP_SHORT_URI,
|
||||
])
|
||||
->assertJsonFragment([
|
||||
'group_id' => $this->group->id
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_store_assigns_created_account_when_default_group_is_the_active_one()
|
||||
{
|
||||
$settingService = resolve('App\Services\SettingServiceInterface');
|
||||
|
||||
// Set the default group to be the active one
|
||||
$settingService->set('defaultGroup', -1);
|
||||
// Set the active group
|
||||
$settingService->set('activeGroup', 1);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/v1/twofaccounts', [
|
||||
'uri' => self::TOTP_SHORT_URI,
|
||||
])
|
||||
->assertJsonFragment([
|
||||
'group_id' => 1
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_store_assigns_created_account_when_default_group_is_no_group()
|
||||
{
|
||||
$settingService = resolve('App\Services\SettingServiceInterface');
|
||||
|
||||
// Set the default group to No group
|
||||
$settingService->set('defaultGroup', 0);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/v1/twofaccounts', [
|
||||
'uri' => self::TOTP_SHORT_URI,
|
||||
])
|
||||
->assertJsonFragment([
|
||||
'group_id' => null
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_store_assigns_created_account_when_default_group_does_not_exist()
|
||||
{
|
||||
$settingService = resolve('App\Services\SettingServiceInterface');
|
||||
|
||||
// Set the default group to a non-existing one
|
||||
$settingService->set('defaultGroup', 1000);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/v1/twofaccounts', [
|
||||
'uri' => self::TOTP_SHORT_URI,
|
||||
])
|
||||
->assertJsonFragment([
|
||||
'group_id' => null
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
|
@ -1,261 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\User;
|
||||
use App\Group;
|
||||
use Tests\TestCase;
|
||||
use App\TwoFAccount;
|
||||
|
||||
class AccountsGroupTest extends TestCase
|
||||
{
|
||||
/** @var \App\User, \App\TwoFAccount, \App\Group */
|
||||
protected $user, $twofaccounts, $group;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
$this->twofaccounts = factory(Twofaccount::class, 3)->create();
|
||||
$this->group = factory(Group::class)->create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test 2FAccounts creation associated to a user group via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testCreateAccountWhenDefaultGroupIsASpecificOne()
|
||||
{
|
||||
|
||||
// Set the default group to the existing one
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'defaultGroup' => $this->group->id,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// Create the account
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/twofaccounts', [
|
||||
'service' => 'testCreation',
|
||||
'account' => 'test@example.org',
|
||||
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
|
||||
'icon' => 'test.png',
|
||||
])
|
||||
->assertStatus(201)
|
||||
->assertJsonFragment([
|
||||
'group_id' => $this->group->id
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test 2FAccounts creation associated to a user group via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testCreateAccountWhenDefaultGroupIsSetToActiveOne()
|
||||
{
|
||||
|
||||
// Set the default group as the active one
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'defaultGroup' => -1,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// Set the active group
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'activeGroup' => 1,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// Create the account
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/twofaccounts', [
|
||||
'service' => 'testCreation',
|
||||
'account' => 'test@example.org',
|
||||
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
|
||||
'icon' => 'test.png',
|
||||
])
|
||||
->assertStatus(201)
|
||||
->assertJsonFragment([
|
||||
'group_id' => 1
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test 2FAccounts creation associated to a user group via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testCreateAccountWhenDefaultIsNoGroup()
|
||||
{
|
||||
|
||||
// Set the default group to No group
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'defaultGroup' => 0,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// Create the account
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/twofaccounts', [
|
||||
'service' => 'testCreation',
|
||||
'account' => 'test@example.org',
|
||||
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
|
||||
'icon' => 'test.png',
|
||||
])
|
||||
->assertStatus(201)
|
||||
->assertJsonMissing([
|
||||
'group_id' => null
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test 2FAccounts creation associated to a user group via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testCreateAccountWhenDefaultGroupDoNotExists()
|
||||
{
|
||||
|
||||
// Set the default group to a non existing one
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'defaultGroup' => 1000,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// Create the account
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/twofaccounts', [
|
||||
'service' => 'testCreation',
|
||||
'account' => 'test@example.org',
|
||||
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
|
||||
'icon' => 'test.png',
|
||||
])
|
||||
->assertStatus(201)
|
||||
->assertJsonMissing([
|
||||
'group_id' => null
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test 2FAccounts association with a user group via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testMoveAccountsToGroup()
|
||||
{
|
||||
// We associate all 3 accounts to the user group
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/group/accounts/', [
|
||||
'groupId' => $this->group->id,
|
||||
'accountsIds' => [1,2,3]
|
||||
])
|
||||
->assertJsonFragment([
|
||||
'id' => $this->group->id,
|
||||
'name' => $this->group->name
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// test if the accounts have the correct foreign key
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/1')
|
||||
->assertJsonFragment([
|
||||
'group_id' => $this->group->id
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/2')
|
||||
->assertJsonFragment([
|
||||
'group_id' => $this->group->id
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/3')
|
||||
->assertJsonFragment([
|
||||
'group_id' => $this->group->id
|
||||
]);
|
||||
|
||||
// test the accounts count of the user group
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/groups')
|
||||
->assertJsonFragment([
|
||||
'twofaccounts_count' => 3
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test 2FAccounts association with a missing group via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testMoveAccountsToMissingGroup()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/group/accounts/', [
|
||||
'groupId' => '1000',
|
||||
'accountsIds' => $this->twofaccounts->keys()
|
||||
])
|
||||
->assertStatus(404);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test 2FAccounts association with the pseudo group via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testMoveAccountsToPseudoGroup()
|
||||
{
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/group/accounts/', [
|
||||
'groupId' => $this->group->id,
|
||||
'accountsIds' => [1,2,3]
|
||||
]);
|
||||
|
||||
// We associate the first account to the pseudo group
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/group/accounts/', [
|
||||
'groupId' => 0,
|
||||
'accountsIds' => [1]
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
|
||||
// test if the forein keys are set to NULL
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/1')
|
||||
->assertJsonFragment([
|
||||
'group_id' => null
|
||||
]);
|
||||
|
||||
// test the accounts count of the group
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/groups')
|
||||
->assertJsonFragment([
|
||||
'twofaccounts_count' => 3, // the 3 accounts for 'all'
|
||||
'twofaccounts_count' => 2 // the 2 accounts that remain in the user group
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Auth\Notifications\ResetPassword;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ForgotPasswordTest extends TestCase
|
||||
{
|
||||
/** @var \App\User */
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Testing submitting the email password request without
|
||||
* email address.
|
||||
*/
|
||||
public function testSubmitEmailPasswordRequestWithoutEmail()
|
||||
{
|
||||
$response = $this->json('POST', '/api/password/email', [
|
||||
'email' => ''
|
||||
]);
|
||||
|
||||
$response->assertStatus(422)
|
||||
->assertJsonValidationErrors(['email']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing submitting the email password request with an invalid
|
||||
* email address.
|
||||
*/
|
||||
public function testSubmitEmailPasswordRequestWithInvalidEmail()
|
||||
{
|
||||
$response = $this->json('POST', '/api/password/email', [
|
||||
'email' => 'nametest.com'
|
||||
]);
|
||||
|
||||
$response->assertStatus(422)
|
||||
->assertJsonValidationErrors(['email']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing submitting the email password request with an unknown
|
||||
* email address.
|
||||
*/
|
||||
public function testSubmitEmailPasswordRequestWithUnknownEmail()
|
||||
{
|
||||
$response = $this->json('POST', '/api/password/email', [
|
||||
'email' => 'name@test.com'
|
||||
]);
|
||||
|
||||
$response->assertStatus(422)
|
||||
->assertJsonValidationErrors(['email']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing submitting the email password request with a valid email address.
|
||||
*/
|
||||
public function testSubmitEmailPasswordRequest()
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$this->user = factory(User::class)->create([
|
||||
'name' => 'user',
|
||||
'email' => 'user@example.org',
|
||||
'password' => bcrypt('password'),
|
||||
'email_verified_at' => now(),
|
||||
'remember_token' => \Illuminate\Support\Str::random(10),
|
||||
]);
|
||||
|
||||
$response = $this->json('POST', '/api/password/email', [
|
||||
'email' => $this->user->email
|
||||
]);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$token = \Illuminate\Support\Facades\DB::table('password_resets')->first();
|
||||
$this->assertNotNull($token);
|
||||
|
||||
Notification::assertSentTo($this->user, ResetPassword::class, function ($notification, $channels) use ($token) {
|
||||
return Hash::check($notification->token, $token->token) === true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing submitting the email password request in Demo mode
|
||||
*/
|
||||
public function testSubmitEmailPasswordRequestInDemoMode()
|
||||
{
|
||||
Config::set('2fauth.config.isDemoApp', true);
|
||||
|
||||
$response = $this->json('POST', '/api/password/email', [
|
||||
'email' => ''
|
||||
]);
|
||||
|
||||
$response->assertStatus(401);
|
||||
}
|
||||
|
||||
}
|
@ -3,18 +3,22 @@
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\User;
|
||||
use Tests\TestCase;
|
||||
use Tests\FeatureTestCase;
|
||||
use Illuminate\Auth\Authenticatable;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Auth\RequestGuard;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
class LoginTest extends TestCase
|
||||
class LoginTest extends FeatureTestCase
|
||||
{
|
||||
/** @var \App\User */
|
||||
/**
|
||||
* @var \App\User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
private const PASSWORD = 'password';
|
||||
private const WRONG_PASSWORD = 'wrong_password';
|
||||
|
||||
/**
|
||||
* @test
|
||||
@ -28,45 +32,38 @@ public function setUp(): void
|
||||
|
||||
|
||||
/**
|
||||
* test User login via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserLogin()
|
||||
public function test_user_login_returns_success()
|
||||
{
|
||||
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'password'
|
||||
'password' => self::PASSWORD
|
||||
])
|
||||
->assertOk()
|
||||
->assertExactJson([
|
||||
'message' => 'authenticated',
|
||||
'name' => $this->user->name,
|
||||
]);
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertJsonStructure([
|
||||
'message' => ['token']
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User login via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserLoginAlreadyAuthenticated()
|
||||
public function test_user_login_already_authenticated_returns_bad_request()
|
||||
{
|
||||
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'password'
|
||||
'password' => self::PASSWORD
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/login', [
|
||||
->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'password'
|
||||
]);
|
||||
|
||||
$response->assertStatus(400)
|
||||
'password' => self::PASSWORD
|
||||
])
|
||||
->assertStatus(400)
|
||||
->assertJson([
|
||||
'message' => __('auth.already_authenticated')
|
||||
]);
|
||||
@ -74,79 +71,71 @@ public function testUserLoginAlreadyAuthenticated()
|
||||
|
||||
|
||||
/**
|
||||
* test User login with missing values via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserLoginWithMissingValues()
|
||||
public function test_user_login_with_missing_data_returns_validation_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => '',
|
||||
'password' => ''
|
||||
])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors([
|
||||
'email',
|
||||
'password'
|
||||
]);
|
||||
|
||||
$response->assertStatus(422)
|
||||
->assertJsonValidationErrors([
|
||||
'email',
|
||||
'password'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User login with invalid credentials via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserLoginWithInvalidCredential()
|
||||
public function test_user_login_with_invalid_credentials_returns_validation_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'badPassword'
|
||||
'password' => self::WRONG_PASSWORD
|
||||
])
|
||||
->assertStatus(401)
|
||||
->assertJson([
|
||||
'message' => 'unauthorised'
|
||||
]);
|
||||
|
||||
$response->assertStatus(401)
|
||||
->assertJson([
|
||||
'message' => 'unauthorised'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User login with invalid credentials via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testTooManyAttempsWithInvalidCredential()
|
||||
public function test_too_many_login_attempts_with_invalid_credentials_returns_too_many_request_error()
|
||||
{
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'badPassword'
|
||||
'password' => self::WRONG_PASSWORD
|
||||
]);
|
||||
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'badPassword'
|
||||
'password' => self::WRONG_PASSWORD
|
||||
]);
|
||||
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'badPassword'
|
||||
'password' => self::WRONG_PASSWORD
|
||||
]);
|
||||
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'badPassword'
|
||||
'password' => self::WRONG_PASSWORD
|
||||
]);
|
||||
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'badPassword'
|
||||
'password' => self::WRONG_PASSWORD
|
||||
]);
|
||||
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'badPassword'
|
||||
'password' => self::WRONG_PASSWORD
|
||||
]);
|
||||
|
||||
$response->assertStatus(429);
|
||||
@ -154,46 +143,47 @@ public function testTooManyAttempsWithInvalidCredential()
|
||||
|
||||
|
||||
/**
|
||||
* test User logout via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserLogout()
|
||||
public function test_user_logout_returns_validation_success()
|
||||
{
|
||||
$response = $this->json('POST', '/api/login', [
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => 'password'
|
||||
'password' => self::PASSWORD
|
||||
]);
|
||||
|
||||
$headers = ['Authorization' => "Bearer " . $response->original['message']['token']];
|
||||
|
||||
$response = $this->json('POST', '/api/logout', [], $headers)
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/user/logout')
|
||||
->assertOk()
|
||||
->assertExactJson([
|
||||
'message' => 'signed out',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User logout after inactivity via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserLogoutAfterInactivity()
|
||||
public function test_user_logout_after_inactivity_returns_unauthorized()
|
||||
{
|
||||
// Set the autolock period to 1 minute
|
||||
$settingService = resolve('App\Services\SettingServiceInterface');
|
||||
$settingService->set('kickUserAfter', 1);
|
||||
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => $this->user->email,
|
||||
'password' => self::PASSWORD
|
||||
]);
|
||||
|
||||
// Ping a protected endpoint to log last_seen_at time
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'kickUserAfter' => '1'])
|
||||
->assertStatus(200);
|
||||
->json('GET', '/api/v1/twofaccounts');
|
||||
|
||||
sleep(61);
|
||||
|
||||
// Ping a restricted endpoint to log last_seen_at time
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/settings/account')
|
||||
->assertStatus(401);
|
||||
->json('GET', '/api/v1/twofaccounts')
|
||||
->assertUnauthorized();
|
||||
}
|
||||
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RegisterTest extends TestCase
|
||||
{
|
||||
/** @var \App\User */
|
||||
protected $user;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Existing user count via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testExistingUserCount()
|
||||
{
|
||||
$response = $this->json('POST', '/api/checkuser')
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'username' => $this->user->name,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test creation of another user via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserCreationWithAnExistingUser()
|
||||
{
|
||||
$response = $this->json('POST', '/api/register', [
|
||||
'name' => 'testCreate',
|
||||
'email' => 'testCreate@example.org',
|
||||
'password' => 'test',
|
||||
'password_confirmation' => 'test',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User creation with missing values via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserCreationWithMissingValues()
|
||||
{
|
||||
// we delete the existing user
|
||||
User::destroy(1);
|
||||
|
||||
$response = $this->json('POST', '/api/register', [
|
||||
'name' => '',
|
||||
'email' => '',
|
||||
'password' => '',
|
||||
'password_confirmation' => '',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User creation with invalid values via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserCreationWithInvalidData()
|
||||
{
|
||||
// we delete the existing user
|
||||
User::destroy(1);
|
||||
|
||||
$response = $this->json('POST', '/api/register', [
|
||||
'name' => 'testInvalid',
|
||||
'email' => 'email',
|
||||
'password' => 'test',
|
||||
'password_confirmation' => 'tset',
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User creation via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserCreation()
|
||||
{
|
||||
|
||||
// we delete the existing user
|
||||
User::destroy(1);
|
||||
|
||||
$response = $this->json('POST', '/api/register', [
|
||||
'name' => 'newUser',
|
||||
'email' => 'newUser@example.org',
|
||||
'password' => 'password',
|
||||
'password_confirmation' => 'password',
|
||||
]);
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertJsonStructure([
|
||||
'message' => ['token', 'name']
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
@ -1,288 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\User;
|
||||
use Tests\TestCase;
|
||||
use App\TwoFAccount;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
class ProtectDbTest extends TestCase
|
||||
{
|
||||
/** @var \App\User, \App\TwoFAccount */
|
||||
protected $user, $twofaccounts;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
$this->twofaccount = factory(Twofaccount::class,)->create([
|
||||
'service' => 'test',
|
||||
'account' => 'test@test.com',
|
||||
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
|
||||
]);
|
||||
$this->twofaccountAlt = factory(Twofaccount::class,)->create([
|
||||
'service' => 'testAlt',
|
||||
'account' => 'testAlt@test.com',
|
||||
'uri' => 'otpauth://totp/testAlt@test.com?secret=A4GRFHVVRBGY7UIW&issuer=testAlt',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test db encryption via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testDbEncryption()
|
||||
{
|
||||
// Encrypt db
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => true,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// Get the raw encrypted records
|
||||
$encrypted = DB::table('twofaccounts')->find($this->twofaccount->id);
|
||||
$encryptedAlt = DB::table('twofaccounts')->find($this->twofaccountAlt->id);
|
||||
|
||||
// Get the accounts via API and check their consistency with raw data
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/' . $this->twofaccount->id)
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'service' => 'test',
|
||||
'account' => Crypt::decryptString($encrypted->account),
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/' . $this->twofaccountAlt->id)
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'service' => 'testAlt',
|
||||
'account' => Crypt::decryptString($encryptedAlt->account),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Account update on protected DB via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testTwofaccountUpdateOnProtectedDb()
|
||||
{
|
||||
// Encrypt db
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => true,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// Only the Account field is encrypted
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PUT', '/api/twofaccounts/' . $this->twofaccount->id, [
|
||||
'service' => 'testUpdate',
|
||||
'account' => 'testUpdate@test.com',
|
||||
'otpType' => 'totp',
|
||||
'secret' => 'A4GRFHVVRBGY7UIW',
|
||||
'secretIsBase32Encoded' => 1,
|
||||
'digits' => 8,
|
||||
'totpPeriod' => 30,
|
||||
'algorithm' => 'sha256',
|
||||
])
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'id' => 1,
|
||||
'service' => 'testUpdate',
|
||||
'account' => 'testUpdate@test.com',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test db encryption via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testPreventDbEncryptionOnDbAlreadyEncrypted()
|
||||
{
|
||||
// Encrypt db
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => true,
|
||||
]);
|
||||
|
||||
// Set the option again to force another encryption pass
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => true,
|
||||
]);
|
||||
|
||||
// Get the account, it should be readable
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/' . $this->twofaccount->id)
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'service' => 'test',
|
||||
'account' => 'test@test.com',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/' . $this->twofaccountAlt->id)
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'service' => 'testAlt',
|
||||
'account' => 'testAlt@test.com',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test db deciphering via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testDbDeciphering()
|
||||
{
|
||||
// Encrypt db
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => true,
|
||||
]);
|
||||
|
||||
// Decipher db
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => false,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// Get the accounts, they should be readable
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/' . $this->twofaccount->id)
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'service' => 'test',
|
||||
'account' => 'test@test.com',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/' . $this->twofaccountAlt->id)
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'service' => 'testAlt',
|
||||
'account' => 'testAlt@test.com',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Protect DB option not being persisted if encryption fails via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testAbortEncryptionIfSomethingGoesWrong()
|
||||
{
|
||||
// Set no APP_KEY to break Laravel encryption capability
|
||||
config(['app.key' => '']);
|
||||
|
||||
// Decipher db
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => true,
|
||||
])
|
||||
->assertStatus(400);
|
||||
|
||||
// Check ProtectDB option is not active
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/settings/options')
|
||||
->assertJsonFragment([
|
||||
'useEncryption' => false
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Protect DB option not being persisted if decyphering fails via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testAbortDecipheringIfSomethingGoesWrong()
|
||||
{
|
||||
// Encrypt db
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => true,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// alter the ciphertext to make deciphering impossible
|
||||
$affected = DB::table('twofaccounts')
|
||||
->where('id', 1)
|
||||
->update(['account' => 'xxxxxxxxx', 'uri' => 'yyyyyyyyy']);
|
||||
|
||||
// Decipher db
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => false,
|
||||
])
|
||||
->assertStatus(400);
|
||||
|
||||
// Check ProtectDB option has been restored
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/settings/options')
|
||||
->assertJsonFragment([
|
||||
'useEncryption' => true
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test bad payload don't breaks anything via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testBadPayloadDontBreakEncryptedAccountFetching()
|
||||
{
|
||||
// Encrypt db
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('POST', '/api/settings/options', [
|
||||
'useEncryption' => true,
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// break the payload
|
||||
DB::table('twofaccounts')
|
||||
->where('id', 1)
|
||||
->update([
|
||||
'account' => 'YouShallNotPass',
|
||||
'uri' => 'PasDeBrasPasDeChocolat',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/1')
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'account' => '*encrypted*',
|
||||
'service' => 'test',
|
||||
'group_id' => null,
|
||||
'isConsistent' => false,
|
||||
'otpType' => null,
|
||||
'digits' => null,
|
||||
'hotpCounter' => null,
|
||||
'totpPeriod' => null,
|
||||
])
|
||||
->assertJsonMissing([
|
||||
'uri' => '*encrypted*',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
class RouteTest extends TestCase
|
||||
class RouteTest extends FeatureTestCase
|
||||
{
|
||||
|
||||
/**
|
||||
@ -12,7 +12,7 @@ class RouteTest extends TestCase
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testLandingViewIsReturned()
|
||||
public function test_landing_view_is_returned()
|
||||
{
|
||||
$response = $this->get(route('landing', ['any' => '/']));
|
||||
|
||||
@ -25,7 +25,7 @@ public function testLandingViewIsReturned()
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testExceptionHandlerWithWebRoute()
|
||||
public function test_exception_handler_with_web_route()
|
||||
{
|
||||
$response = $this->post('/');
|
||||
|
197
tests/Feature/Services/AppstractOptionsServiceTest.php
Normal file
197
tests/Feature/Services/AppstractOptionsServiceTest.php
Normal file
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Tests\FeatureTestCase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AppstractOptionsServiceTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
* App\Services\SettingServiceInterface $settingService
|
||||
*/
|
||||
protected $settingService;
|
||||
|
||||
private const KEY = 'key';
|
||||
private const VALUE = 'value';
|
||||
private const SETTING_NAME = 'MySetting';
|
||||
private const SETTING_NAME_ALT = 'MySettingAlt';
|
||||
private const SETTING_VALUE_STRING = 'MyValue';
|
||||
private const SETTING_VALUE_TRUE_TRANSFORMED = '{{1}}';
|
||||
private const SETTING_VALUE_FALSE_TRANSFORMED = '{{}}';
|
||||
private const SETTING_VALUE_INT = 10;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->settingService = $this->app->make('App\Services\SettingServiceInterface');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_get_string_setting_returns_correct_value()
|
||||
{
|
||||
DB::table('options')->insert(
|
||||
[self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_STRING)]
|
||||
);
|
||||
|
||||
$this->assertEquals(self::SETTING_VALUE_STRING, $this->settingService->get(self::SETTING_NAME));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_get_boolean_setting_returns_true()
|
||||
{
|
||||
DB::table('options')->insert(
|
||||
[self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_TRUE_TRANSFORMED)]
|
||||
);
|
||||
|
||||
$this->assertEquals(true, $this->settingService->get(self::SETTING_NAME));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_get_boolean_setting_returns_false()
|
||||
{
|
||||
DB::table('options')->insert(
|
||||
[self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_FALSE_TRANSFORMED)]
|
||||
);
|
||||
|
||||
$this->assertEquals(false, $this->settingService->get(self::SETTING_NAME));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_get_int_setting_returns_int()
|
||||
{
|
||||
DB::table('options')->insert(
|
||||
[self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_INT)]
|
||||
);
|
||||
|
||||
$value = $this->settingService->get(self::SETTING_NAME);
|
||||
|
||||
$this->assertEquals(self::SETTING_VALUE_INT, $value);
|
||||
$this->assertIsInt($value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_all_returns_native_and_user_settings()
|
||||
{
|
||||
$native_options = config('2fauth.options');
|
||||
|
||||
DB::table('options')->insert(
|
||||
[self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_STRING)]
|
||||
);
|
||||
|
||||
$all = $this->settingService->all();
|
||||
|
||||
$this->assertCount(count($native_options)+1, $all);
|
||||
|
||||
$this->assertArrayHasKey(self::SETTING_NAME, $all);
|
||||
$this->assertEquals($all[self::SETTING_NAME], self::SETTING_VALUE_STRING);
|
||||
|
||||
foreach ($native_options as $key => $val) {
|
||||
$this->assertArrayHasKey($key, $all);
|
||||
$this->assertEquals($all[$key], $val);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_set_setting_persist_correct_value()
|
||||
{
|
||||
$value = $this->settingService->set(self::SETTING_NAME, self::SETTING_VALUE_STRING);
|
||||
|
||||
$this->assertDatabaseHas('options', [
|
||||
self::KEY => self::SETTING_NAME,
|
||||
self::VALUE => self::SETTING_VALUE_STRING
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_set_array_of_settings_persist_correct_values()
|
||||
{
|
||||
$value = $this->settingService->set([
|
||||
self::SETTING_NAME => self::SETTING_VALUE_STRING,
|
||||
self::SETTING_NAME_ALT => self::SETTING_VALUE_INT,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('options', [
|
||||
self::KEY => self::SETTING_NAME,
|
||||
self::VALUE => self::SETTING_VALUE_STRING
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('options', [
|
||||
self::KEY => self::SETTING_NAME_ALT,
|
||||
self::VALUE => self::SETTING_VALUE_INT
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_set_true_setting_persist_transformed_boolean()
|
||||
{
|
||||
$value = $this->settingService->set(self::SETTING_NAME, true);
|
||||
|
||||
$this->assertDatabaseHas('options', [
|
||||
self::KEY => self::SETTING_NAME,
|
||||
self::VALUE => self::SETTING_VALUE_TRUE_TRANSFORMED
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_set_false_setting_persist_transformed_boolean()
|
||||
{
|
||||
$value = $this->settingService->set(self::SETTING_NAME, false);
|
||||
|
||||
$this->assertDatabaseHas('options', [
|
||||
self::KEY => self::SETTING_NAME,
|
||||
self::VALUE => self::SETTING_VALUE_FALSE_TRANSFORMED
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_del_remove_setting_from_db()
|
||||
{
|
||||
DB::table('options')->insert(
|
||||
[self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_STRING)]
|
||||
);
|
||||
|
||||
$value = $this->settingService->delete(self::SETTING_NAME);
|
||||
|
||||
$this->assertDatabaseMissing('options', [
|
||||
self::KEY => self::SETTING_NAME,
|
||||
self::VALUE => self::SETTING_VALUE_STRING
|
||||
]);
|
||||
}
|
||||
}
|
621
tests/Feature/Services/TwoFAccountServiceTest.php
Normal file
621
tests/Feature/Services/TwoFAccountServiceTest.php
Normal file
@ -0,0 +1,621 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\TwoFAccount;
|
||||
use Tests\FeatureTestCase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
|
||||
/**
|
||||
* @covers \App\Services\TwoFAccountService
|
||||
*/
|
||||
class TwoFAccountServiceTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
* App\Services\SettingServiceInterface $settingService
|
||||
*/
|
||||
protected $twofaccountService;
|
||||
|
||||
|
||||
/**
|
||||
* App\TwoFAccount $customTotpTwofaccount
|
||||
*/
|
||||
protected $customTotpTwofaccount;
|
||||
|
||||
|
||||
/**
|
||||
* App\TwoFAccount $customTotpTwofaccount
|
||||
*/
|
||||
protected $customHotpTwofaccount;
|
||||
|
||||
private const ACCOUNT = 'account';
|
||||
private const SERVICE = 'service';
|
||||
private const SECRET = 'A4GRFHVVRBGY7UIW';
|
||||
private const ALGORITHM_DEFAULT = 'sha1';
|
||||
private const ALGORITHM_CUSTOM = 'sha256';
|
||||
private const DIGITS_DEFAULT = 6;
|
||||
private const DIGITS_CUSTOM = 7;
|
||||
private const PERIOD_DEFAULT = 30;
|
||||
private const PERIOD_CUSTOM = 40;
|
||||
private const COUNTER_DEFAULT = 0;
|
||||
private const COUNTER_CUSTOM = 5;
|
||||
private const IMAGE = 'https%3A%2F%2Fen.opensuse.org%2Fimages%2F4%2F44%2FButton-filled-colour.png';
|
||||
private const ICON = 'test.png';
|
||||
private const TOTP_FULL_CUSTOM_URI = 'otpauth://totp/'.self::SERVICE.':'.self::ACCOUNT.'?secret='.self::SECRET.'&issuer='.self::SERVICE.'&digits='.self::DIGITS_CUSTOM.'&period='.self::PERIOD_CUSTOM.'&algorithm='.self::ALGORITHM_CUSTOM.'&image='.self::IMAGE;
|
||||
private const HOTP_FULL_CUSTOM_URI = 'otpauth://hotp/'.self::SERVICE.':'.self::ACCOUNT.'?secret='.self::SECRET.'&issuer='.self::SERVICE.'&digits='.self::DIGITS_CUSTOM.'&counter='.self::COUNTER_CUSTOM.'&algorithm='.self::ALGORITHM_CUSTOM.'&image='.self::IMAGE;
|
||||
private const TOTP_SHORT_URI = 'otpauth://totp/'.self::ACCOUNT.'?secret='.self::SECRET;
|
||||
private const HOTP_SHORT_URI = 'otpauth://hotp/'.self::ACCOUNT.'?secret='.self::SECRET;
|
||||
private const TOTP_URI_WITH_UNREACHABLE_IMAGE = 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&image=https%3A%2F%2Fen.opensuse.org%2Fimage.png';
|
||||
private const INVALID_OTPAUTH_URI = 'otpauth://Xotp/'.self::ACCOUNT.'?secret='.self::SECRET;
|
||||
private const ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP = [
|
||||
'service' => self::SERVICE,
|
||||
'account' => self::ACCOUNT,
|
||||
'icon' => self::ICON,
|
||||
'otp_type' => 'totp',
|
||||
'secret' => self::SECRET,
|
||||
'digits' => self::DIGITS_CUSTOM,
|
||||
'algorithm' => self::ALGORITHM_CUSTOM,
|
||||
'period' => self::PERIOD_CUSTOM,
|
||||
'counter' => null,
|
||||
];
|
||||
private const ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP = [
|
||||
'account' => self::ACCOUNT,
|
||||
'otp_type' => 'totp',
|
||||
'secret' => self::SECRET,
|
||||
];
|
||||
private const ARRAY_OF_PARAMETERS_FOR_UNSUPPORTED_OTP_TYPE = [
|
||||
'account' => self::ACCOUNT,
|
||||
'otp_type' => 'Xotp',
|
||||
'secret' => self::SECRET,
|
||||
];
|
||||
private const ARRAY_OF_INVALID_PARAMETERS_FOR_TOTP = [
|
||||
'account' => self::ACCOUNT,
|
||||
'otp_type' => 'totp',
|
||||
'secret' => 0,
|
||||
];
|
||||
private const ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP = [
|
||||
'service' => self::SERVICE,
|
||||
'account' => self::ACCOUNT,
|
||||
'icon' => self::ICON,
|
||||
'otp_type' => 'hotp',
|
||||
'secret' => self::SECRET,
|
||||
'digits' => self::DIGITS_CUSTOM,
|
||||
'algorithm' => self::ALGORITHM_CUSTOM,
|
||||
'period' => null,
|
||||
'counter' => self::COUNTER_CUSTOM,
|
||||
];
|
||||
private const ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_HOTP = [
|
||||
'account' => self::ACCOUNT,
|
||||
'otp_type' => 'hotp',
|
||||
'secret' => self::SECRET,
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->twofaccountService = $this->app->make('App\Services\TwoFAccountService');
|
||||
|
||||
$this->customTotpTwofaccount = new TwoFAccount;
|
||||
$this->customTotpTwofaccount->legacy_uri = self::TOTP_FULL_CUSTOM_URI;
|
||||
$this->customTotpTwofaccount->service = self::SERVICE;
|
||||
$this->customTotpTwofaccount->account = self::ACCOUNT;
|
||||
$this->customTotpTwofaccount->icon = self::ICON;
|
||||
$this->customTotpTwofaccount->otp_type = 'totp';
|
||||
$this->customTotpTwofaccount->secret = self::SECRET;
|
||||
$this->customTotpTwofaccount->digits = self::DIGITS_CUSTOM;
|
||||
$this->customTotpTwofaccount->algorithm = self::ALGORITHM_CUSTOM;
|
||||
$this->customTotpTwofaccount->period = self::PERIOD_CUSTOM;
|
||||
$this->customTotpTwofaccount->counter = null;
|
||||
$this->customTotpTwofaccount->save();
|
||||
|
||||
$this->customHotpTwofaccount = new TwoFAccount;
|
||||
$this->customHotpTwofaccount->legacy_uri = self::HOTP_FULL_CUSTOM_URI;
|
||||
$this->customHotpTwofaccount->service = self::SERVICE;
|
||||
$this->customHotpTwofaccount->account = self::ACCOUNT;
|
||||
$this->customHotpTwofaccount->icon = self::ICON;
|
||||
$this->customHotpTwofaccount->otp_type = 'hotp';
|
||||
$this->customHotpTwofaccount->secret = self::SECRET;
|
||||
$this->customHotpTwofaccount->digits = self::DIGITS_CUSTOM;
|
||||
$this->customHotpTwofaccount->algorithm = self::ALGORITHM_CUSTOM;
|
||||
$this->customHotpTwofaccount->period = null;
|
||||
$this->customHotpTwofaccount->counter = self::COUNTER_CUSTOM;
|
||||
$this->customHotpTwofaccount->save();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_custom_totp_from_uri_returns_correct_value()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromUri(self::TOTP_FULL_CUSTOM_URI);
|
||||
|
||||
$this->assertEquals('totp', $twofaccount->otp_type);
|
||||
$this->assertEquals(self::TOTP_FULL_CUSTOM_URI, $twofaccount->legacy_uri);
|
||||
$this->assertEquals(self::SERVICE, $twofaccount->service);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_CUSTOM, $twofaccount->digits);
|
||||
$this->assertEquals(self::PERIOD_CUSTOM, $twofaccount->period);
|
||||
$this->assertEquals(null, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_CUSTOM, $twofaccount->algorithm);
|
||||
$this->assertStringEndsWith('.png',$twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_basic_totp_from_uri_returns_default_value()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromUri(self::TOTP_SHORT_URI);
|
||||
|
||||
$this->assertEquals('totp', $twofaccount->otp_type);
|
||||
$this->assertEquals(self::TOTP_SHORT_URI, $twofaccount->legacy_uri);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(null, $twofaccount->service);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_DEFAULT, $twofaccount->digits);
|
||||
$this->assertEquals(self::PERIOD_DEFAULT, $twofaccount->period);
|
||||
$this->assertEquals(null, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_DEFAULT, $twofaccount->algorithm);
|
||||
$this->assertEquals(null, $twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_custom_hotp_from_uri_returns_correct_value()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromUri(self::HOTP_FULL_CUSTOM_URI);
|
||||
|
||||
$this->assertEquals('hotp', $twofaccount->otp_type);
|
||||
$this->assertEquals(self::HOTP_FULL_CUSTOM_URI, $twofaccount->legacy_uri);
|
||||
$this->assertEquals(self::SERVICE, $twofaccount->service);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_CUSTOM, $twofaccount->digits);
|
||||
$this->assertEquals(null, $twofaccount->period);
|
||||
$this->assertEquals(self::COUNTER_CUSTOM, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_CUSTOM, $twofaccount->algorithm);
|
||||
$this->assertStringEndsWith('.png',$twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_basic_hotp_from_uri_returns_default_value()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromUri(self::HOTP_SHORT_URI);
|
||||
|
||||
$this->assertEquals('hotp', $twofaccount->otp_type);
|
||||
$this->assertEquals(self::HOTP_SHORT_URI, $twofaccount->legacy_uri);
|
||||
$this->assertEquals(null, $twofaccount->service);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_DEFAULT, $twofaccount->digits);
|
||||
$this->assertEquals(null, $twofaccount->period);
|
||||
$this->assertEquals(self::COUNTER_DEFAULT, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_DEFAULT, $twofaccount->algorithm);
|
||||
$this->assertEquals(null, $twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_from_uri_persists_to_db()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromUri(self::TOTP_SHORT_URI);
|
||||
|
||||
$this->assertDatabaseHas('twofaccounts', [
|
||||
'otp_type' => 'totp',
|
||||
'legacy_uri' => self::TOTP_SHORT_URI,
|
||||
'service' => null,
|
||||
'account' => self::ACCOUNT,
|
||||
'secret' => self::SECRET,
|
||||
'digits' => self::DIGITS_DEFAULT,
|
||||
'period' => self::PERIOD_DEFAULT,
|
||||
'counter' => null,
|
||||
'algorithm' => self::ALGORITHM_DEFAULT,
|
||||
'icon' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_from_uri_does_not_persist_to_db()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromUri(self::TOTP_SHORT_URI, false);
|
||||
|
||||
$this->assertDatabaseMissing('twofaccounts', [
|
||||
'otp_type' => 'totp',
|
||||
'legacy_uri' => self::TOTP_SHORT_URI,
|
||||
'service' => null,
|
||||
'account' => self::ACCOUNT,
|
||||
'secret' => self::SECRET,
|
||||
'digits' => self::DIGITS_DEFAULT,
|
||||
'period' => self::PERIOD_DEFAULT,
|
||||
'counter' => null,
|
||||
'algorithm' => self::ALGORITHM_DEFAULT,
|
||||
'icon' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_from_invalid_uri_returns_ValidationException()
|
||||
{
|
||||
$this->expectException(\Illuminate\Validation\ValidationException::class);
|
||||
$twofaccount = $this->twofaccountService->createFromUri(self::INVALID_OTPAUTH_URI);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_from_uri_without_label_returns_ValidationException()
|
||||
{
|
||||
$this->expectException(\Illuminate\Validation\ValidationException::class);
|
||||
$twofaccount = $this->twofaccountService->createFromUri('otpauth://totp/?secret='.self::SECRET);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_custom_totp_from_parameters_returns_correct_value()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromParameters(self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP);
|
||||
|
||||
$this->assertEquals('totp', $twofaccount->otp_type);
|
||||
$this->assertEquals(self::SERVICE, $twofaccount->service);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_CUSTOM, $twofaccount->digits);
|
||||
$this->assertEquals(self::PERIOD_CUSTOM, $twofaccount->period);
|
||||
$this->assertEquals(null, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_CUSTOM, $twofaccount->algorithm);
|
||||
$this->assertStringEndsWith('.png',$twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_basic_totp_from_parameters_returns_correct_value()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromParameters(self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP);
|
||||
|
||||
$this->assertEquals('totp', $twofaccount->otp_type);
|
||||
$this->assertEquals(null, $twofaccount->service);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_DEFAULT, $twofaccount->digits);
|
||||
$this->assertEquals(self::PERIOD_DEFAULT, $twofaccount->period);
|
||||
$this->assertEquals(null, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_DEFAULT, $twofaccount->algorithm);
|
||||
$this->assertEquals(null, $twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_custom_hotp_from_parameters_returns_correct_value()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromParameters(self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP);
|
||||
|
||||
$this->assertEquals('hotp', $twofaccount->otp_type);
|
||||
$this->assertEquals(self::SERVICE, $twofaccount->service);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_CUSTOM, $twofaccount->digits);
|
||||
$this->assertEquals(null, $twofaccount->period);
|
||||
$this->assertEquals(self::COUNTER_CUSTOM, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_CUSTOM, $twofaccount->algorithm);
|
||||
$this->assertStringEndsWith('.png',$twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_basic_hotp_from_parameters_returns_correct_value()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromParameters(self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_HOTP);
|
||||
|
||||
$this->assertEquals('hotp', $twofaccount->otp_type);
|
||||
$this->assertEquals(null, $twofaccount->service);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_DEFAULT, $twofaccount->digits);
|
||||
$this->assertEquals(null, $twofaccount->period);
|
||||
$this->assertEquals(self::COUNTER_DEFAULT, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_DEFAULT, $twofaccount->algorithm);
|
||||
$this->assertEquals(null, $twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_from_parameters_persists_to_db()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromParameters(self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP);
|
||||
|
||||
$this->assertDatabaseHas('twofaccounts', [
|
||||
'otp_type' => 'totp',
|
||||
'legacy_uri' => self::TOTP_SHORT_URI,
|
||||
'service' => null,
|
||||
'account' => self::ACCOUNT,
|
||||
'secret' => self::SECRET,
|
||||
'digits' => self::DIGITS_DEFAULT,
|
||||
'period' => self::PERIOD_DEFAULT,
|
||||
'counter' => null,
|
||||
'algorithm' => self::ALGORITHM_DEFAULT,
|
||||
'icon' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_from_parameters_does_not_persist_to_db()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->createFromParameters(self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP, false);
|
||||
|
||||
$this->assertDatabaseMissing('twofaccounts', [
|
||||
'otp_type' => 'totp',
|
||||
'legacy_uri' => self::TOTP_SHORT_URI,
|
||||
'service' => null,
|
||||
'account' => self::ACCOUNT,
|
||||
'secret' => self::SECRET,
|
||||
'digits' => self::DIGITS_DEFAULT,
|
||||
'period' => self::PERIOD_DEFAULT,
|
||||
'counter' => null,
|
||||
'algorithm' => self::ALGORITHM_DEFAULT,
|
||||
'icon' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_from_unsupported_parameters_returns_ValidationException()
|
||||
{
|
||||
$this->expectException(\Illuminate\Validation\ValidationException::class);
|
||||
$twofaccount = $this->twofaccountService->createFromParameters(self::ARRAY_OF_PARAMETERS_FOR_UNSUPPORTED_OTP_TYPE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_from_invalid_parameters_type_returns_InvalidOtpParameterException()
|
||||
{
|
||||
$this->expectException(\App\Exceptions\InvalidOtpParameterException::class);
|
||||
$twofaccount = $this->twofaccountService->createFromParameters([
|
||||
'account' => self::ACCOUNT,
|
||||
'otp_type' => 'totp',
|
||||
'digits' => 'notsupported',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_create_from_invalid_parameters_returns_InvalidOtpParameterException()
|
||||
{
|
||||
$this->expectException(\App\Exceptions\InvalidOtpParameterException::class);
|
||||
$twofaccount = $this->twofaccountService->createFromParameters([
|
||||
'account' => self::ACCOUNT,
|
||||
'otp_type' => 'totp',
|
||||
'algorithm' => 'notsupported',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_totp_returns_updated_model()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->update($this->customTotpTwofaccount, self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP);
|
||||
|
||||
$this->assertEquals('totp', $twofaccount->otp_type);
|
||||
$this->assertEquals(null, $twofaccount->service);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_DEFAULT, $twofaccount->digits);
|
||||
$this->assertEquals(self::PERIOD_DEFAULT, $twofaccount->period);
|
||||
$this->assertEquals(null, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_DEFAULT, $twofaccount->algorithm);
|
||||
$this->assertEquals(null, $twofaccount->counter);
|
||||
$this->assertEquals(null, $twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_hotp_returns_updated_model()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->update($this->customTotpTwofaccount, self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_HOTP);
|
||||
|
||||
$this->assertEquals('hotp', $twofaccount->otp_type);
|
||||
$this->assertEquals(null, $twofaccount->service);
|
||||
$this->assertEquals(self::ACCOUNT, $twofaccount->account);
|
||||
$this->assertEquals(self::SECRET, $twofaccount->secret);
|
||||
$this->assertEquals(self::DIGITS_DEFAULT, $twofaccount->digits);
|
||||
$this->assertEquals(null, $twofaccount->period);
|
||||
$this->assertEquals(self::COUNTER_DEFAULT, $twofaccount->counter);
|
||||
$this->assertEquals(self::ALGORITHM_DEFAULT, $twofaccount->algorithm);
|
||||
$this->assertEquals(null, $twofaccount->counter);
|
||||
$this->assertEquals(null, $twofaccount->icon);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_totp_persists_updated_model()
|
||||
{
|
||||
$twofaccount = $this->twofaccountService->update($this->customTotpTwofaccount, self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP);
|
||||
|
||||
$this->assertDatabaseHas('twofaccounts', [
|
||||
'otp_type' => 'totp',
|
||||
'service' => null,
|
||||
'account' => self::ACCOUNT,
|
||||
'secret' => self::SECRET,
|
||||
'digits' => self::DIGITS_DEFAULT,
|
||||
'period' => self::PERIOD_DEFAULT,
|
||||
'counter' => null,
|
||||
'algorithm' => self::ALGORITHM_DEFAULT,
|
||||
'icon' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_getOTP_for_totp_returns_the_same_password()
|
||||
{
|
||||
$otp_from_model = $this->twofaccountService->getOTP($this->customTotpTwofaccount);
|
||||
$otp_from_id = $this->twofaccountService->getOTP($this->customTotpTwofaccount->id);
|
||||
$otp_from_uri = $this->twofaccountService->getOTP(self::TOTP_FULL_CUSTOM_URI);
|
||||
|
||||
// Those assertions may fail if the 3 previous assignments are not done at the same exact timestamp
|
||||
$this->assertEquals($otp_from_model, $otp_from_id);
|
||||
$this->assertEquals($otp_from_model, $otp_from_uri);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_getOTP_for_hotp_returns_the_same_password()
|
||||
{
|
||||
$otp_from_model = $this->twofaccountService->getOTP($this->customHotpTwofaccount);
|
||||
$otp_from_id = $this->twofaccountService->getOTP($this->customHotpTwofaccount->id);
|
||||
$otp_from_uri = $this->twofaccountService->getOTP(self::HOTP_FULL_CUSTOM_URI);
|
||||
|
||||
// Those assertions may fail if the 3 previous assignments are not done at the same exact timestamp
|
||||
$this->assertEquals($otp_from_model, $otp_from_id);
|
||||
$this->assertEquals($otp_from_model, $otp_from_uri);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_getOTP_for_totp_with_invalid_secret_returns_InvalidSecretException()
|
||||
{
|
||||
$this->expectException(\App\Exceptions\InvalidSecretException::class);
|
||||
$otp_from_uri = $this->twofaccountService->getOTP('otpauth://totp/'.self::ACCOUNT.'?secret=0');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_getURI_for_custom_totp_model_returns_uri()
|
||||
{
|
||||
$uri = $this->twofaccountService->getURI($this->customTotpTwofaccount);
|
||||
|
||||
$this->assertStringContainsString('otpauth://totp/', $uri);
|
||||
$this->assertStringContainsString(self::SERVICE, $uri);
|
||||
$this->assertStringContainsString(self::ACCOUNT, $uri);
|
||||
$this->assertStringContainsString('secret='.self::SECRET, $uri);
|
||||
$this->assertStringContainsString('digits='.self::DIGITS_CUSTOM, $uri);
|
||||
$this->assertStringContainsString('period='.self::PERIOD_CUSTOM, $uri);
|
||||
$this->assertStringContainsString('algorithm='.self::ALGORITHM_CUSTOM, $uri);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_getURI_for_custom_totp_model_id_returns_uri()
|
||||
{
|
||||
$uri = $this->twofaccountService->getURI($this->customTotpTwofaccount->id);
|
||||
|
||||
$this->assertStringContainsString('otpauth://totp/', $uri);
|
||||
$this->assertStringContainsString(self::SERVICE, $uri);
|
||||
$this->assertStringContainsString(self::ACCOUNT, $uri);
|
||||
$this->assertStringContainsString('secret='.self::SECRET, $uri);
|
||||
$this->assertStringContainsString('digits='.self::DIGITS_CUSTOM, $uri);
|
||||
$this->assertStringContainsString('period='.self::PERIOD_CUSTOM, $uri);
|
||||
$this->assertStringContainsString('algorithm='.self::ALGORITHM_CUSTOM, $uri);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_getURI_for_custom_hotp_model_returns_uri()
|
||||
{
|
||||
$uri = $this->twofaccountService->getURI($this->customHotpTwofaccount);
|
||||
|
||||
$this->assertStringContainsString('otpauth://hotp/', $uri);
|
||||
$this->assertStringContainsString(self::SERVICE, $uri);
|
||||
$this->assertStringContainsString(self::ACCOUNT, $uri);
|
||||
$this->assertStringContainsString('secret='.self::SECRET, $uri);
|
||||
$this->assertStringContainsString('digits='.self::DIGITS_CUSTOM, $uri);
|
||||
$this->assertStringContainsString('counter='.self::COUNTER_CUSTOM, $uri);
|
||||
$this->assertStringContainsString('algorithm='.self::ALGORITHM_CUSTOM, $uri);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_getURI_for_custom_hotp_model_id_returns_uri()
|
||||
{
|
||||
$uri = $this->twofaccountService->getURI($this->customHotpTwofaccount->id);
|
||||
|
||||
$this->assertStringContainsString('otpauth://hotp/', $uri);
|
||||
$this->assertStringContainsString(self::SERVICE, $uri);
|
||||
$this->assertStringContainsString(self::ACCOUNT, $uri);
|
||||
$this->assertStringContainsString('secret='.self::SECRET, $uri);
|
||||
$this->assertStringContainsString('digits='.self::DIGITS_CUSTOM, $uri);
|
||||
$this->assertStringContainsString('counter='.self::COUNTER_CUSTOM, $uri);
|
||||
$this->assertStringContainsString('algorithm='.self::ALGORITHM_CUSTOM, $uri);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_getURI_for_totp_dto_returns_uri()
|
||||
{
|
||||
$dto = new \App\Services\Dto\TwoFAccountDto;
|
||||
|
||||
$dto->otp_type = 'totp';
|
||||
$dto->account = self::ACCOUNT;
|
||||
$dto->secret = self::SECRET;
|
||||
|
||||
$uri = $this->twofaccountService->getURI($dto);
|
||||
|
||||
$this->assertStringContainsString('otpauth://totp/', $uri);
|
||||
$this->assertStringContainsString(self::ACCOUNT, $uri);
|
||||
$this->assertStringContainsString('secret='.self::SECRET, $uri);
|
||||
}
|
||||
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\User;
|
||||
use Tests\TestCase;
|
||||
use App\TwoFAccount;
|
||||
use App\Http\Controllers\TwoFAccountController;
|
||||
use Illuminate\Auth\Authenticatable;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Auth\RequestGuard;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class ApiExceptionTest extends TestCase
|
||||
{
|
||||
/** @var \App\User */
|
||||
protected $user;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Unauthorized
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testHttpUnauthenticated()
|
||||
{
|
||||
$response = $this->json('GET', '/api/settings/options')
|
||||
->assertStatus(401)
|
||||
->assertJson([
|
||||
'message' => 'Unauthenticated.'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Not Found
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testHttpNotFound()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('GET', '/api/twofaccounts/1000')
|
||||
->assertStatus(404);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Method Not Allowed
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testHttpMethodNotAllowed()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/settings/options')
|
||||
->assertStatus(405);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Unprocessable entity
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testHttpUnprocessableEntity()
|
||||
{
|
||||
$response = $this->json('POST', '/api/login')
|
||||
->assertStatus(422)
|
||||
->assertJsonStructure([
|
||||
'message',
|
||||
'errors'
|
||||
])
|
||||
->assertJsonValidationErrors([
|
||||
'email',
|
||||
'password'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Internal Server error
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testHttpInternalServerError()
|
||||
{
|
||||
factory(TwoFAccount::class, 3)->create();
|
||||
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/twofaccounts/reorder', [
|
||||
'orderedIds' => 'x'])
|
||||
->assertStatus(500);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Settings;
|
||||
|
||||
use App\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AccountTest extends TestCase
|
||||
{
|
||||
/** @var \App\User */
|
||||
protected $user;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test Get user infos via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testGetUserDetails()
|
||||
{
|
||||
$user = User::find(1);
|
||||
|
||||
$response = $this->actingAs($user, 'api')
|
||||
->json('GET', '/api/settings/account')
|
||||
->assertStatus(200)
|
||||
->assertJsonStructure(['name', 'email']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User update with wrong current password via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserUpdateWithWrongCurrentPassword()
|
||||
{
|
||||
$user = User::find(1);
|
||||
|
||||
$response = $this->actingAs($user, 'api')
|
||||
->json('PATCH', '/api/settings/account', [
|
||||
'name' => 'userUpdated',
|
||||
'email' => 'userUpdated@example.org',
|
||||
'password' => 'wrongPassword',
|
||||
]);
|
||||
|
||||
$response->assertStatus(400)
|
||||
->assertJsonStructure(['message']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User update via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testUserUpdate()
|
||||
{
|
||||
$user = User::find(1);
|
||||
|
||||
$response = $this->actingAs($user, 'api')
|
||||
->json('PATCH', '/api/settings/account', [
|
||||
'name' => 'userUpdated',
|
||||
'email' => 'userUpdated@example.org',
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'username' => 'userUpdated'
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Settings;
|
||||
|
||||
use App\User;
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class PasswordTest extends TestCase
|
||||
{
|
||||
/** @var \App\User */
|
||||
protected $user;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = factory(User::class)->create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User password update with wrong current password via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testPasswordUpdateWithWrongCurrentPassword()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/settings/password', [
|
||||
'currentPassword' => 'wrongPassword',
|
||||
'password' => 'passwordUpdated',
|
||||
'password_confirmation' => 'passwordUpdated',
|
||||
]);
|
||||
|
||||
$response->assertStatus(400)
|
||||
->assertJsonStructure(['message']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test User password update via API
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function testPasswordUpdate()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api')
|
||||
->json('PATCH', '/api/settings/password', [
|
||||
'currentPassword' => 'password',
|
||||
'password' => 'passwordUpdated',
|
||||
'password_confirmation' => 'passwordUpdated',
|
||||
]);
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertJsonStructure(['message']);
|
||||
|
||||
$this->user->refresh();
|
||||
|
||||
$this->assertTrue(Hash::check('passwordUpdated', $this->user->password));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user