mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-06-25 06:24:07 +02:00
Enhance test coverage
This commit is contained in:
parent
c717e6b279
commit
9c5f18bb46
@ -21,7 +21,7 @@ class WebauthnTwoFAuthUserProvider extends WebAuthnUserProvider
|
||||
return $this->validateWebAuthn();
|
||||
}
|
||||
|
||||
// If the user disabled the fallback is enabled, we will validate the credential password.
|
||||
// If the user disabled the fallback, we will validate the credential password.
|
||||
return $user->preferences['useWebauthnOnly'] == false && EloquentUserProvider::validateCredentials($user, $credentials);
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ class GroupPolicy
|
||||
* @param \App\Models\User $user
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function viewAny(User $user)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// public function viewAny(User $user)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
@ -48,19 +48,19 @@ class GroupPolicy
|
||||
* @param \Illuminate\Support\Collection<int, \App\Models\Group> $groups
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function viewEach(User $user, Group $group, $groups)
|
||||
{
|
||||
$can = $this->isOwnerOfEach($user, $groups);
|
||||
// public function viewEach(User $user, Group $group, $groups)
|
||||
// {
|
||||
// $can = $this->isOwnerOfEach($user, $groups);
|
||||
|
||||
if (! $can) {
|
||||
$ids = $groups->map(function ($group, $key) {
|
||||
return $group->id;
|
||||
});
|
||||
Log::notice(sprintf('User ID #%s cannot view all groups in IDs #%s', $user->id, implode(',', $ids->toArray())));
|
||||
}
|
||||
// if (! $can) {
|
||||
// $ids = $groups->map(function ($group, $key) {
|
||||
// return $group->id;
|
||||
// });
|
||||
// Log::notice(sprintf('User ID #%s cannot view all groups in IDs #%s', $user->id, implode(',', $ids->toArray())));
|
||||
// }
|
||||
|
||||
return $can;
|
||||
}
|
||||
// return $can;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
@ -101,19 +101,19 @@ class GroupPolicy
|
||||
* @param \Illuminate\Support\Collection<int, \App\Models\Group> $groups
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function updateEach(User $user, Group $group, $groups)
|
||||
{
|
||||
$can = $this->isOwnerOfEach($user, $groups);
|
||||
// public function updateEach(User $user, Group $group, $groups)
|
||||
// {
|
||||
// $can = $this->isOwnerOfEach($user, $groups);
|
||||
|
||||
if (! $can) {
|
||||
$ids = $groups->map(function ($group, $key) {
|
||||
return $group->id;
|
||||
});
|
||||
Log::notice(sprintf('User ID #%s cannot update all groups in IDs #%s', $user->id, implode(',', $ids->toArray())));
|
||||
}
|
||||
// if (! $can) {
|
||||
// $ids = $groups->map(function ($group, $key) {
|
||||
// return $group->id;
|
||||
// });
|
||||
// Log::notice(sprintf('User ID #%s cannot update all groups in IDs #%s', $user->id, implode(',', $ids->toArray())));
|
||||
// }
|
||||
|
||||
return $can;
|
||||
}
|
||||
// return $can;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
@ -141,19 +141,19 @@ class GroupPolicy
|
||||
* @param \Illuminate\Support\Collection<int, \App\Models\Group> $groups
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function deleteEach(User $user, Group $group, $groups)
|
||||
{
|
||||
$can = $this->isOwnerOfEach($user, $groups);
|
||||
// public function deleteEach(User $user, Group $group, $groups)
|
||||
// {
|
||||
// $can = $this->isOwnerOfEach($user, $groups);
|
||||
|
||||
if (! $can) {
|
||||
$ids = $groups->map(function ($group, $key) {
|
||||
return $group->id;
|
||||
});
|
||||
Log::notice(sprintf('User ID #%s cannot delete all groups in IDs #%s', $user->id, implode(',', $ids->toArray())));
|
||||
}
|
||||
// if (! $can) {
|
||||
// $ids = $groups->map(function ($group, $key) {
|
||||
// return $group->id;
|
||||
// });
|
||||
// Log::notice(sprintf('User ID #%s cannot delete all groups in IDs #%s', $user->id, implode(',', $ids->toArray())));
|
||||
// }
|
||||
|
||||
return $can;
|
||||
}
|
||||
// return $can;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
@ -162,10 +162,10 @@ class GroupPolicy
|
||||
* @param \App\Models\Group $group
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function restore(User $user, Group $group)
|
||||
{
|
||||
return $this->isOwnerOf($user, $group);
|
||||
}
|
||||
// public function restore(User $user, Group $group)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
@ -174,8 +174,8 @@ class GroupPolicy
|
||||
* @param \App\Models\Group $group
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function forceDelete(User $user, Group $group)
|
||||
{
|
||||
return $this->isOwnerOf($user, $group);
|
||||
}
|
||||
// public function forceDelete(User $user, Group $group)
|
||||
// {
|
||||
|
||||
// }
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ class TwoFAccountPolicy
|
||||
* @param \App\Models\User $user
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function viewAny(User $user)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// public function viewAny(User $user)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
@ -162,10 +162,10 @@ class TwoFAccountPolicy
|
||||
* @param \App\Models\TwoFAccount $twofaccount
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function restore(User $user, TwoFAccount $twofaccount)
|
||||
{
|
||||
return $this->isOwnerOf($user, $twofaccount);
|
||||
}
|
||||
// public function restore(User $user, TwoFAccount $twofaccount)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
@ -174,8 +174,8 @@ class TwoFAccountPolicy
|
||||
* @param \App\Models\TwoFAccount $twofaccount
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function forceDelete(User $user, TwoFAccount $twofaccount)
|
||||
{
|
||||
return $this->isOwnerOf($user, $twofaccount);
|
||||
}
|
||||
// public function forceDelete(User $user, TwoFAccount $twofaccount)
|
||||
// {
|
||||
|
||||
// }
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class TwoFAuthMigrator extends Migrator
|
||||
|
||||
if (is_null($json)) {
|
||||
Log::error('2FAuth JSON migration data cannot be read');
|
||||
throw new InvalidMigrationDataException('2FAS Auth');
|
||||
throw new InvalidMigrationDataException('2FAuth');
|
||||
}
|
||||
|
||||
$twofaccounts = [];
|
||||
|
@ -10,6 +10,9 @@ use Tests\FeatureTestCase;
|
||||
/**
|
||||
* @covers \App\Api\v1\Controllers\GroupController
|
||||
* @covers \App\Api\v1\Resources\GroupResource
|
||||
* @covers \App\Listeners\ResetUsersPreference
|
||||
* @covers \App\Policies\GroupPolicy
|
||||
* @covers \App\Models\Group
|
||||
*/
|
||||
class GroupControllerTest extends FeatureTestCase
|
||||
{
|
||||
@ -444,4 +447,27 @@ class GroupControllerTest extends FeatureTestCase
|
||||
'message',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_destroy_group_resets_user_preferences()
|
||||
{
|
||||
// Set the default group to a specific one
|
||||
$this->user['preferences->defaultGroup'] = $this->userGroupA->id;
|
||||
// Set the active group
|
||||
$this->user['preferences->activeGroup'] = $this->userGroupA->id;
|
||||
$this->user->save();
|
||||
|
||||
$this->assertEquals($this->userGroupA->id, $this->user->preferences['defaultGroup']);
|
||||
$this->assertEquals($this->userGroupA->id, $this->user->preferences['activeGroup']);
|
||||
|
||||
$this->actingAs($this->user, 'api-guard')
|
||||
->json('DELETE', '/api/v1/groups/' . $this->userGroupA->id);
|
||||
|
||||
$this->user->refresh();
|
||||
|
||||
$this->assertEquals(0, $this->user->preferences['defaultGroup']);
|
||||
$this->assertEquals(0, $this->user->preferences['activeGroup']);
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,14 @@ use Tests\FeatureTestCase;
|
||||
|
||||
/**
|
||||
* @covers \App\Api\v1\Controllers\TwoFAccountController
|
||||
* @covers \App\Api\v1\Resources\TwoFAccountCollection
|
||||
* @covers \App\Api\v1\Resources\TwoFAccountReadResource
|
||||
* @covers \App\Api\v1\Resources\TwoFAccountStoreResource
|
||||
* @covers \App\Api\v1\Resources\TwoFAccountExportResource
|
||||
* @covers \App\Api\v1\Resources\TwoFAccountExportCollection
|
||||
* @covers \App\Providers\MigrationServiceProvider
|
||||
* @covers \App\Providers\TwoFAuthServiceProvider
|
||||
* @covers \App\Policies\TwoFAccountPolicy
|
||||
*/
|
||||
class TwoFAccountControllerTest extends FeatureTestCase
|
||||
{
|
||||
@ -91,6 +95,27 @@ class TwoFAccountControllerTest extends FeatureTestCase
|
||||
'counter',
|
||||
];
|
||||
|
||||
private const VALID_EXPORT_STRUTURE = [
|
||||
'app',
|
||||
'schema',
|
||||
'datetime',
|
||||
'data' => [
|
||||
'*' => [
|
||||
'otp_type',
|
||||
'account',
|
||||
'service',
|
||||
'icon',
|
||||
'icon_mime',
|
||||
'icon_file',
|
||||
'secret',
|
||||
'digits',
|
||||
'algorithm',
|
||||
'period',
|
||||
'counter',
|
||||
'legacy_uri',
|
||||
], ],
|
||||
];
|
||||
|
||||
private const JSON_FRAGMENTS_FOR_CUSTOM_TOTP = [
|
||||
'service' => OtpTestData::SERVICE,
|
||||
'account' => OtpTestData::ACCOUNT,
|
||||
@ -868,6 +893,65 @@ class TwoFAccountControllerTest extends FeatureTestCase
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_export_returns_json_migration_resource()
|
||||
{
|
||||
$this->twofaccountA = TwoFAccount::factory()->for($this->user)->create(self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP);
|
||||
$this->twofaccountB = TwoFAccount::factory()->for($this->user)->create(self::JSON_FRAGMENTS_FOR_DEFAULT_HOTP);
|
||||
|
||||
$this->actingAs($this->user, 'api-guard')
|
||||
->json('GET', '/api/v1/twofaccounts/export?ids=' . $this->twofaccountA->id . ',' . $this->twofaccountB->id)
|
||||
->assertOk()
|
||||
->assertJsonStructure(self::VALID_EXPORT_STRUTURE)
|
||||
->assertJsonFragment(self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP)
|
||||
->assertJsonFragment(self::JSON_FRAGMENTS_FOR_DEFAULT_HOTP);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_export_too_many_ids_returns_bad_request()
|
||||
{
|
||||
TwoFAccount::factory()->count(102)->for($this->user)->create();
|
||||
|
||||
$ids = DB::table('twofaccounts')->where('user_id', $this->user->id)->pluck('id')->implode(',');
|
||||
|
||||
$response = $this->actingAs($this->user, 'api-guard')
|
||||
->json('GET', '/api/v1/twofaccounts/export?ids=' . $ids)
|
||||
->assertStatus(400)
|
||||
->assertJsonStructure([
|
||||
'message',
|
||||
'reason',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_export_missing_twofaccount_returns_existing_ones_only()
|
||||
{
|
||||
$this->twofaccountA = TwoFAccount::factory()->for($this->user)->create(self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP);
|
||||
|
||||
$response = $this->actingAs($this->user, 'api-guard')
|
||||
->json('GET', '/api/v1/twofaccounts/export?ids=' . $this->twofaccountA->id . ',1000')
|
||||
->assertJsonFragment(self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_export_twofaccount_of_another_user_is_forbidden()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'api-guard')
|
||||
->json('GET', '/api/v1/twofaccounts/export?ids=' . $this->twofaccountC->id)
|
||||
->assertForbidden()
|
||||
->assertJsonStructure([
|
||||
'message',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
@ -1155,8 +1239,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
|
||||
{
|
||||
TwoFAccount::factory()->count(3)->for($this->user)->create();
|
||||
|
||||
$ids = DB::table('twofaccounts')->where('user_id', $this->user->id)->pluck('id')->implode(',');
|
||||
|
||||
$response = $this->actingAs($this->user, 'api-guard')
|
||||
->json('DELETE', '/api/v1/twofaccounts?ids=' . $this->twofaccountA->id . ',' . $this->twofaccountB->id)
|
||||
->assertNoContent();
|
||||
|
@ -106,7 +106,7 @@ class MigrationTestData
|
||||
"name": "' . OtpTestData::ACCOUNT . '",
|
||||
"issuer": "' . OtpTestData::SERVICE . '",
|
||||
"note": "",
|
||||
"icon": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiPg0KICAgPGNpcmNsZSBjeD0iNTEyIiBjeT0iNTEyIiByPSI1MTIiIHN0eWxlPSJmaWxsOiMwMDBlOWMiLz4NCiAgIDxwYXRoIGQ9Im03MDAuMiA0NjYuNSA2MS4yLTEwNi4zYzIzLjYgNDEuNiAzNy4yIDg5LjggMzcuMiAxNDEuMSAwIDY4LjgtMjQuMyAxMzEuOS02NC43IDE4MS40SDU3NS44bDQ4LjctODQuNmgtNjQuNGw3NS44LTEzMS43IDY0LjMuMXptLTU1LjQtMTI1LjJMNDQ4LjMgNjgyLjVsLjEuMkgyOTAuMWMtNDAuNS00OS41LTY0LjctMTEyLjYtNjQuNy0xODEuNCAwLTUxLjQgMTMuNi05OS42IDM3LjMtMTQxLjNsMTAyLjUgMTc4LjIgMTEzLjMtMTk3aDE2Ni4zeiIgc3R5bGU9ImZpbGw6I2ZmZiIvPg0KPC9zdmc+DQo=",
|
||||
"icon": "' . OtpTestData::ICON_SVG_DATA_ENCODED . '",
|
||||
"icon_mime": "image\/svg+xml",
|
||||
"info": {
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
@ -463,4 +463,249 @@ class MigrationTestData
|
||||
},
|
||||
"db": "1rX0ajzsxNbhN2hvnNCMBNooLlzqwz\/LMT3bNEIJjPH+zIvIbA6GVVPHLpna+yvjxLPKVkt1OQig=="
|
||||
}';
|
||||
|
||||
const VALID_2FAUTH_JSON_MIGRATION_PAYLOAD = '
|
||||
{
|
||||
"app": "2fauth_v3.4.1",
|
||||
"schema": 1,
|
||||
"datetime": "2022-12-14T14:53:06.173939Z",
|
||||
"data":
|
||||
[
|
||||
{
|
||||
"otp_type": "totp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": null,
|
||||
"icon_mime": null,
|
||||
"icon_file": null,
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::TOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
},
|
||||
{
|
||||
"otp_type": "hotp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": null,
|
||||
"icon_mime": null,
|
||||
"icon_file": null,
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": null,
|
||||
"counter": ' . OtpTestData::COUNTER_CUSTOM . ',
|
||||
"legacy_uri": "' . OtpTestData::HOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
},
|
||||
{
|
||||
"otp_type": "steamtotp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::STEAM . '",
|
||||
"icon": null,
|
||||
"icon_mime": null,
|
||||
"icon_file": null,
|
||||
"secret": "' . OtpTestData::STEAM_SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_STEAM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::STEAM_TOTP_URI . '"
|
||||
}
|
||||
]
|
||||
}';
|
||||
|
||||
const VALID_2FAUTH_MIGRATION_PAYLOAD_WITH_UNSUPPORTED_OTP_TYPE = '
|
||||
{
|
||||
"app": "2fauth_v3.4.1",
|
||||
"schema": 1,
|
||||
"datetime": "2022-12-14T14:53:06.173939Z",
|
||||
"data":
|
||||
[
|
||||
{
|
||||
"otp_type": "totp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": null,
|
||||
"icon_mime": null,
|
||||
"icon_file": null,
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::TOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
},
|
||||
{
|
||||
"otp_type": "Xotp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": null,
|
||||
"icon_mime": null,
|
||||
"icon_file": null,
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::TOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
}
|
||||
]
|
||||
}';
|
||||
|
||||
const VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_SVG_ICON = '
|
||||
{
|
||||
"app": "2fauth_v3.4.1",
|
||||
"schema": 1,
|
||||
"datetime": "2022-12-14T14:53:06.173939Z",
|
||||
"data":
|
||||
[
|
||||
{
|
||||
"otp_type": "totp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": "' . OtpTestData::ICON_SVG . '",
|
||||
"icon_mime": "image\/svg+xml",
|
||||
"icon_file": "' . OtpTestData::ICON_SVG_DATA_ENCODED . '",
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::TOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
}
|
||||
]
|
||||
}';
|
||||
|
||||
const VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_JPG_ICON = '
|
||||
{
|
||||
"app": "2fauth_v3.4.1",
|
||||
"schema": 1,
|
||||
"datetime": "2022-12-14T14:53:06.173939Z",
|
||||
"data":
|
||||
[
|
||||
{
|
||||
"otp_type": "totp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": "' . OtpTestData::ICON_JPEG . '",
|
||||
"icon_mime": "image\/svg+xml",
|
||||
"icon_file": "' . OtpTestData::ICON_JPEG_DATA . '",
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::TOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
}
|
||||
]
|
||||
}';
|
||||
|
||||
const VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_PNG_ICON = '
|
||||
{
|
||||
"app": "2fauth_v3.4.1",
|
||||
"schema": 1,
|
||||
"datetime": "2022-12-14T14:53:06.173939Z",
|
||||
"data":
|
||||
[
|
||||
{
|
||||
"otp_type": "totp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": "' . OtpTestData::ICON_PNG . '",
|
||||
"icon_mime": "image\/svg+xml",
|
||||
"icon_file": "' . OtpTestData::ICON_PNG_DATA . '",
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::TOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
}
|
||||
]
|
||||
}';
|
||||
|
||||
const VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_BMP_ICON = '
|
||||
{
|
||||
"app": "2fauth_v3.4.1",
|
||||
"schema": 1,
|
||||
"datetime": "2022-12-14T14:53:06.173939Z",
|
||||
"data":
|
||||
[
|
||||
{
|
||||
"otp_type": "totp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": "' . OtpTestData::ICON_BMP . '",
|
||||
"icon_mime": "image\/svg+xml",
|
||||
"icon_file": "' . OtpTestData::ICON_BMP_DATA . '",
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::TOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
}
|
||||
]
|
||||
}';
|
||||
|
||||
const VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_WEBP_ICON = '
|
||||
{
|
||||
"app": "2fauth_v3.4.1",
|
||||
"schema": 1,
|
||||
"datetime": "2022-12-14T14:53:06.173939Z",
|
||||
"data":
|
||||
[
|
||||
{
|
||||
"otp_type": "totp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": "' . OtpTestData::ICON_WEBP . '",
|
||||
"icon_mime": "image\/svg+xml",
|
||||
"icon_file": "' . OtpTestData::ICON_WEBP_DATA . '",
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::TOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
}
|
||||
]
|
||||
}';
|
||||
|
||||
const VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_UNSUPPORTED_ICON = '
|
||||
{
|
||||
"app": "2fauth_v3.4.1",
|
||||
"schema": 1,
|
||||
"datetime": "2022-12-14T14:53:06.173939Z",
|
||||
"data":
|
||||
[
|
||||
{
|
||||
"otp_type": "totp",
|
||||
"account": "' . OtpTestData::ACCOUNT . '",
|
||||
"service": "' . OtpTestData::SERVICE . '",
|
||||
"icon": "' . OtpTestData::ICON_PNG . '",
|
||||
"icon_mime": "image\/gif",
|
||||
"icon_file": "' . OtpTestData::ICON_PNG_DATA . '",
|
||||
"secret": "' . OtpTestData::SECRET . '",
|
||||
"digits": ' . OtpTestData::DIGITS_CUSTOM . ',
|
||||
"algorithm": "' . OtpTestData::ALGORITHM_CUSTOM . '",
|
||||
"period": ' . OtpTestData::PERIOD_CUSTOM . ',
|
||||
"counter": null,
|
||||
"legacy_uri": "' . OtpTestData::TOTP_FULL_CUSTOM_URI_NO_IMG . '"
|
||||
}
|
||||
]
|
||||
}';
|
||||
|
||||
const INVALID_2FAUTH_JSON_MIGRATION_PAYLOAD = '
|
||||
{
|
||||
"app": "2fauth_v3.4.1",
|
||||
"schema": 1,
|
||||
"datetime": "2022-12-14T14:53:06.173939Z",
|
||||
"data":
|
||||
[
|
||||
,
|
||||
]
|
||||
}';
|
||||
}
|
||||
|
@ -54,6 +54,8 @@ class OtpTestData
|
||||
|
||||
const ICON_SVG_DATA = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><circle cx="512" cy="512" r="512" style="fill:#000e9c"/><path d="m700.2 466.5 61.2-106.3c23.6 41.6 37.2 89.8 37.2 141.1 0 68.8-24.3 131.9-64.7 181.4H575.8l48.7-84.6h-64.4l75.8-131.7 64.3.1zm-55.4-125.2L448.3 682.5l.1.2H290.1c-40.5-49.5-64.7-112.6-64.7-181.4 0-51.4 13.6-99.6 37.3-141.3l102.5 178.2 113.3-197h166.3z" style="fill:#fff"/></svg>';
|
||||
|
||||
const ICON_SVG_DATA_ENCODED = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiPg0KICAgPGNpcmNsZSBjeD0iNTEyIiBjeT0iNTEyIiByPSI1MTIiIHN0eWxlPSJmaWxsOiMwMDBlOWMiLz4NCiAgIDxwYXRoIGQ9Im03MDAuMiA0NjYuNSA2MS4yLTEwNi4zYzIzLjYgNDEuNiAzNy4yIDg5LjggMzcuMiAxNDEuMSAwIDY4LjgtMjQuMyAxMzEuOS02NC43IDE4MS40SDU3NS44bDQ4LjctODQuNmgtNjQuNGw3NS44LTEzMS43IDY0LjMuMXptLTU1LjQtMTI1LjJMNDQ4LjMgNjgyLjVsLjEuMkgyOTAuMWMtNDAuNS00OS41LTY0LjctMTEyLjYtNjQuNy0xODEuNCAwLTUxLjQgMTMuNi05OS42IDM3LjMtMTQxLjNsMTAyLjUgMTc4LjIgMTEzLjMtMTk3aDE2Ni4zeiIgc3R5bGU9ImZpbGw6I2ZmZiIvPg0KPC9zdmc+DQo=';
|
||||
|
||||
const TOTP_FULL_CUSTOM_URI_NO_IMG = 'otpauth://totp/' . self::SERVICE . ':' . self::ACCOUNT . '?secret=' . self::SECRET . '&issuer=' . self::SERVICE . '&digits=' . self::DIGITS_CUSTOM . '&period=' . self::PERIOD_CUSTOM . '&algorithm=' . self::ALGORITHM_CUSTOM;
|
||||
|
||||
const TOTP_FULL_CUSTOM_URI = self::TOTP_FULL_CUSTOM_URI_NO_IMG . '&image=' . self::IMAGE;
|
||||
|
@ -7,6 +7,7 @@ use Tests\FeatureTestCase;
|
||||
|
||||
/**
|
||||
* @covers \App\Http\Controllers\Auth\RegisterController
|
||||
* @covers \App\Http\Requests\UserStoreRequest
|
||||
*/
|
||||
class RegisterControllerTest extends FeatureTestCase
|
||||
{
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Tests\Feature\Http\Auth;
|
||||
|
||||
use App\Facades\Settings;
|
||||
use App\Models\Group;
|
||||
use App\Models\TwoFAccount;
|
||||
use App\Models\User;
|
||||
@ -12,6 +11,7 @@ use Tests\FeatureTestCase;
|
||||
/**
|
||||
* @covers \App\Http\Controllers\Auth\UserController
|
||||
* @covers \App\Http\Middleware\RejectIfDemoMode
|
||||
* @covers \App\Http\Requests\UserUpdateRequest
|
||||
*/
|
||||
class UserControllerTest extends FeatureTestCase
|
||||
{
|
||||
@ -63,6 +63,33 @@ class UserControllerTest extends FeatureTestCase
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_update_user_with_uppercased_email_returns_success()
|
||||
{
|
||||
$response = $this->actingAs($this->user, 'web-guard')
|
||||
->json('PUT', '/user', [
|
||||
'name' => self::NEW_USERNAME,
|
||||
'email' => strtoupper(self::NEW_EMAIL),
|
||||
'password' => self::PASSWORD,
|
||||
])
|
||||
->assertOk()
|
||||
->assertExactJson([
|
||||
'name' => self::NEW_USERNAME,
|
||||
'id' => $this->user->id,
|
||||
'email' => self::NEW_EMAIL,
|
||||
'is_admin' => false,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'name' => self::NEW_USERNAME,
|
||||
'id' => $this->user->id,
|
||||
'email' => self::NEW_EMAIL,
|
||||
'is_admin' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
|
@ -12,6 +12,7 @@ use Tests\FeatureTestCase;
|
||||
/**
|
||||
* @covers \App\Http\Controllers\Auth\WebAuthnLoginController
|
||||
* @covers \App\Models\User
|
||||
* @covers \App\Extensions\WebauthnTwoFAuthUserProvider
|
||||
*/
|
||||
class WebAuthnLoginControllerTest extends FeatureTestCase
|
||||
{
|
||||
@ -175,6 +176,26 @@ class WebAuthnLoginControllerTest extends FeatureTestCase
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_legacy_login_is_rejected_when_webauthn_only_is_enable()
|
||||
{
|
||||
$this->user = User::factory()->create([
|
||||
'email' => self::EMAIL,
|
||||
]);
|
||||
|
||||
// Set to webauthn only
|
||||
$this->user['preferences->useWebauthnOnly'] = true;
|
||||
$this->user->save();
|
||||
|
||||
$response = $this->json('POST', '/user/login', [
|
||||
'email' => self::EMAIL,
|
||||
'password' => 'password',
|
||||
])
|
||||
->assertUnauthorized();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
@ -289,7 +310,7 @@ class WebAuthnLoginControllerTest extends FeatureTestCase
|
||||
false,
|
||||
)]);
|
||||
|
||||
for ($i=0; $i < $throttle - 1; $i++) {
|
||||
for ($i = 0; $i < $throttle - 1; $i++) {
|
||||
$this->json('POST', '/webauthn/login', self::ASSERTION_RESPONSE_INVALID);
|
||||
}
|
||||
|
||||
|
54
tests/Feature/Http/Middlewares/AdminOnlyMiddlewareTest.php
Normal file
54
tests/Feature/Http/Middlewares/AdminOnlyMiddlewareTest.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Http\Middlewares;
|
||||
|
||||
use App\Http\Middleware\AdminOnly;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Http\Request;
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
class AdminOnlyMiddlewareTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_users_are_rejected()
|
||||
{
|
||||
$this->expectException(AuthorizationException::class);
|
||||
|
||||
/**
|
||||
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
|
||||
*/
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$request = Request::create('/admin', 'GET');
|
||||
$middleware = new AdminOnly;
|
||||
|
||||
$response = $middleware->handle($request, function () {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_admins_pass()
|
||||
{
|
||||
/**
|
||||
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
|
||||
*/
|
||||
$admin = User::factory()->administrator()->create();
|
||||
|
||||
$this->actingAs($admin);
|
||||
|
||||
$request = Request::create('/admin', 'GET');
|
||||
$middleware = new AdminOnly;
|
||||
|
||||
$response = $middleware->handle($request, function () {
|
||||
});
|
||||
|
||||
$this->assertNull($response);
|
||||
}
|
||||
}
|
80
tests/Feature/Http/Requests/WebauthnAssertedRequestTest.php
Normal file
80
tests/Feature/Http/Requests/WebauthnAssertedRequestTest.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Http\Requests;
|
||||
|
||||
use App\Http\Requests\WebauthnAssertedRequest;
|
||||
use Illuminate\Foundation\Testing\WithoutMiddleware;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \App\Http\Requests\WebauthnAssertedRequest
|
||||
*/
|
||||
class WebauthnAssertedRequestTest extends TestCase
|
||||
{
|
||||
use WithoutMiddleware;
|
||||
|
||||
/**
|
||||
* @dataProvider provideValidData
|
||||
*/
|
||||
public function test_valid_data(array $data) : void
|
||||
{
|
||||
$request = new WebauthnAssertedRequest();
|
||||
$validator = Validator::make($data, $request->rules());
|
||||
|
||||
$this->assertFalse($validator->fails());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide Valid data for validation test
|
||||
*/
|
||||
public function provideValidData() : array
|
||||
{
|
||||
return [
|
||||
[[
|
||||
'id' => 'string',
|
||||
'rawId' => 'string',
|
||||
'type' => 'string',
|
||||
'response' => [
|
||||
'clientDataJSON' => 'string',
|
||||
'authenticatorData' => 'string',
|
||||
'signature' => 'string',
|
||||
'userHandle' => null,
|
||||
],
|
||||
'email' => 'valid@email.com',
|
||||
]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInvalidData
|
||||
*/
|
||||
public function test_invalid_data(array $data) : void
|
||||
{
|
||||
$request = new WebauthnAssertedRequest();
|
||||
$validator = Validator::make($data, $request->rules());
|
||||
|
||||
$this->assertTrue($validator->fails());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide invalid data for validation test
|
||||
*/
|
||||
public function provideInvalidData() : array
|
||||
{
|
||||
return [
|
||||
[[
|
||||
'email' => '', // required
|
||||
]],
|
||||
[[
|
||||
'email' => true, // email
|
||||
]],
|
||||
[[
|
||||
'email' => 0, // email
|
||||
]],
|
||||
[[
|
||||
'email' => 'sdfsdf@', // email
|
||||
]],
|
||||
];
|
||||
}
|
||||
}
|
35
tests/Feature/Models/UserModelTest.php
Normal file
35
tests/Feature/Models/UserModelTest.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Models;
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
/**
|
||||
* @covers \App\Models\User
|
||||
*/
|
||||
class UserModelTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_admin_scope_returns_only_admin()
|
||||
{
|
||||
User::factory()->count(4)->create();
|
||||
|
||||
$firstAdmin = User::factory()->administrator()->create([
|
||||
'name' => 'first',
|
||||
]);
|
||||
$secondAdmin = User::factory()->administrator()->create([
|
||||
'name' => 'secondAdmin',
|
||||
]);
|
||||
|
||||
$admins = User::admins()->get();
|
||||
|
||||
$this->assertCount(2, $admins);
|
||||
$this->assertEquals($admins[0]->is_admin, true);
|
||||
$this->assertEquals($admins[1]->is_admin, true);
|
||||
$this->assertEquals($admins[0]->name, $firstAdmin->name);
|
||||
$this->assertEquals($admins[1]->name, $secondAdmin->name);
|
||||
}
|
||||
}
|
@ -174,4 +174,29 @@ class HandlerTest extends TestCase
|
||||
'message',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_AccessDeniedException_returns_forbidden_json_response()
|
||||
{
|
||||
$request = $this->createMock(Request::class);
|
||||
$instance = new Handler($this->createMock(Container::class));
|
||||
$class = new \ReflectionClass(Handler::class);
|
||||
|
||||
$method = $class->getMethod('render');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$mockException = $this->createMock(\Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException::class);
|
||||
|
||||
$response = $method->invokeArgs($instance, [$request, $mockException]);
|
||||
|
||||
$this->assertInstanceOf(JsonResponse::class, $response);
|
||||
|
||||
$response = \Illuminate\Testing\TestResponse::fromBaseResponse($response);
|
||||
$response->assertStatus(403)
|
||||
->assertJsonStructure([
|
||||
'message',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -135,4 +135,98 @@ class HelpersTest extends TestCase
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @dataProvider commaSeparatedToArrayProvider
|
||||
*/
|
||||
public function test_commaSeparatedToArray_returns_ids_in_array($str, $expected)
|
||||
{
|
||||
$array = Helpers::commaSeparatedToArray($str);
|
||||
|
||||
$this->assertEquals($expected, $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide data for cleanVersionNumber() tests
|
||||
*/
|
||||
public function commaSeparatedToArrayProvider()
|
||||
{
|
||||
return [
|
||||
'NOMINAL' => [
|
||||
'1,2,3',
|
||||
[1, 2, 3],
|
||||
],
|
||||
'DUPLICATE' => [
|
||||
'1,2,2,3',
|
||||
[1, 2, 2, 3],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @dataProvider invalidCommaSeparatedToArrayProvider
|
||||
*/
|
||||
public function test_commaSeparatedToArray_returns_unchanged_ids($str, $expected)
|
||||
{
|
||||
$array = Helpers::commaSeparatedToArray($str);
|
||||
|
||||
$this->assertEquals($expected, $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide data for cleanVersionNumber() tests
|
||||
*/
|
||||
public function invalidCommaSeparatedToArrayProvider()
|
||||
{
|
||||
return [
|
||||
'INVALID_IDS_LEADING_SPACES' => [
|
||||
'1, 2,3',
|
||||
'1, 2,3',
|
||||
],
|
||||
'INVALID_IDS_TRAILING_SPACES' => [
|
||||
'1,2 ,3',
|
||||
'1,2 ,3',
|
||||
],
|
||||
'INVALID_IDS_BAD_SEPARATOR' => [
|
||||
'1/2/3',
|
||||
'1/2/3',
|
||||
],
|
||||
'INVALID_IDS_NOT_DIGIT' => [
|
||||
'a,b,c',
|
||||
'a,b,c',
|
||||
],
|
||||
'INVALID_IDS_MISSING_DIGIT' => [
|
||||
'1,,3',
|
||||
'1,,3',
|
||||
],
|
||||
'INVALID_IDS_LEADING_COMMA' => [
|
||||
',2,3',
|
||||
',2,3',
|
||||
],
|
||||
'INVALID_IDS_TRAILING_COMMA' => [
|
||||
'1,2,',
|
||||
'1,2,',
|
||||
],
|
||||
'NOT_STRING_BOOLEAN' => [
|
||||
true,
|
||||
true,
|
||||
],
|
||||
'NOT_STRING_INT' => [
|
||||
1,
|
||||
1,
|
||||
],
|
||||
'NOT_STRING_ARRAY' => [
|
||||
[1],
|
||||
[1],
|
||||
],
|
||||
'NOT_STRING_NULL' => [
|
||||
null,
|
||||
null,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ use App\Services\Migrators\GoogleAuthMigrator;
|
||||
use App\Services\Migrators\Migrator;
|
||||
use App\Services\Migrators\PlainTextMigrator;
|
||||
use App\Services\Migrators\TwoFASMigrator;
|
||||
use App\Services\Migrators\TwoFAuthMigrator;
|
||||
use App\Services\SettingService;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Mockery;
|
||||
@ -30,6 +31,7 @@ use Tests\TestCase;
|
||||
* @covers \App\Services\Migrators\TwoFASMigrator
|
||||
* @covers \App\Services\Migrators\PlainTextMigrator
|
||||
* @covers \App\Services\Migrators\GoogleAuthMigrator
|
||||
* @covers \App\Services\Migrators\TwoFAuthMigrator
|
||||
*
|
||||
* @uses \App\Models\TwoFAccount
|
||||
*/
|
||||
@ -208,6 +210,12 @@ class MigratorTest extends TestCase
|
||||
'gauth',
|
||||
$hasSteam = false,
|
||||
],
|
||||
'2FAUTH_MIGRATION_PAYLOAD' => [
|
||||
new TwoFAuthMigrator(),
|
||||
MigrationTestData::VALID_2FAUTH_JSON_MIGRATION_PAYLOAD,
|
||||
'custom',
|
||||
$hasSteam = true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -273,6 +281,10 @@ class MigratorTest extends TestCase
|
||||
new GoogleAuthMigrator(),
|
||||
MigrationTestData::GOOGLE_AUTH_MIGRATION_URI_WITH_INVALID_DATA,
|
||||
],
|
||||
'INVALID_2FAUTH_JSON_MIGRATION_PAYLOAD' => [
|
||||
new TwoFAuthMigrator(),
|
||||
MigrationTestData::INVALID_2FAUTH_JSON_MIGRATION_PAYLOAD,
|
||||
],
|
||||
|
||||
];
|
||||
}
|
||||
@ -313,6 +325,10 @@ class MigratorTest extends TestCase
|
||||
new TwoFASMigrator(),
|
||||
MigrationTestData::VALID_2FAS_MIGRATION_PAYLOAD_WITH_UNSUPPORTED_OTP_TYPE,
|
||||
],
|
||||
'VALID_2FAUTH_MIGRATION_PAYLOAD_WITH_UNSUPPORTED_OTP_TYPE' => [
|
||||
new TwoFAuthMigrator(),
|
||||
MigrationTestData::VALID_2FAUTH_MIGRATION_PAYLOAD_WITH_UNSUPPORTED_OTP_TYPE,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -394,12 +410,71 @@ class MigratorTest extends TestCase
|
||||
Storage::disk('icons')->assertDirectoryEmpty('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @dataProvider TwoFAuthWithIconMigrationProvider
|
||||
*/
|
||||
public function test_migrate_2fauth_payload_with_icon_sets_and_stores_the_icon($migration)
|
||||
{
|
||||
Storage::fake('icons');
|
||||
|
||||
$migrator = new TwoFAuthMigrator();
|
||||
$accounts = $migrator->migrate($migration);
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(TwoFAccount::class, $accounts);
|
||||
$this->assertCount(1, $accounts);
|
||||
|
||||
Storage::disk('icons')->assertExists($accounts->first()->icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide data for TwoFAccount store tests
|
||||
*/
|
||||
public function TwoFAuthWithIconMigrationProvider()
|
||||
{
|
||||
return [
|
||||
'SVG' => [
|
||||
MigrationTestData::VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_SVG_ICON,
|
||||
],
|
||||
'PNG' => [
|
||||
MigrationTestData::VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_PNG_ICON,
|
||||
],
|
||||
'JPG' => [
|
||||
MigrationTestData::VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_JPG_ICON,
|
||||
],
|
||||
'BMP' => [
|
||||
MigrationTestData::VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_BMP_ICON,
|
||||
],
|
||||
'WEBP' => [
|
||||
MigrationTestData::VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_WEBP_ICON,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_migrate_2fauth_payload_with_unsupported_icon_does_not_fail()
|
||||
{
|
||||
Storage::fake('icons');
|
||||
|
||||
$migrator = new TwoFAuthMigrator();
|
||||
$accounts = $migrator->migrate(MigrationTestData::VALID_2FAUTH_JSON_MIGRATION_PAYLOAD_WITH_UNSUPPORTED_ICON);
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(TwoFAccount::class, $accounts);
|
||||
$this->assertCount(1, $accounts);
|
||||
|
||||
$this->assertNull($this->fakeTwofaccount->icon);
|
||||
Storage::disk('icons')->assertDirectoryEmpty('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @dataProvider factoryProvider
|
||||
*/
|
||||
public function test_factory_returns_plain_text_migrator($payload, $migratorClass)
|
||||
public function test_factory_returns_relevant_migrator($payload, $migratorClass)
|
||||
{
|
||||
$factory = new MigratorFactory();
|
||||
|
||||
@ -434,6 +509,10 @@ class MigratorTest extends TestCase
|
||||
MigrationTestData::GOOGLE_AUTH_MIGRATION_URI,
|
||||
GoogleAuthMigrator::class,
|
||||
],
|
||||
'2FAUTH_MIGRATION_URI' => [
|
||||
MigrationTestData::VALID_2FAUTH_JSON_MIGRATION_PAYLOAD,
|
||||
TwoFAuthMigrator::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user