浏览代码

Fix and complete tests

Bubka 3 年之前
父节点
当前提交
ee22e24cf1
共有 34 个文件被更改,包括 1179 次插入227 次删除
  1. 9 0
      .env.testing
  2. 8 0
      app/Extensions/RemoteUserProvider.php
  3. 2 0
      app/Http/Controllers/Auth/UserController.php
  4. 0 15
      app/Http/Controllers/Auth/WebAuthnDeviceLostController.php
  5. 3 1
      app/Http/Controllers/Auth/WebAuthnLoginController.php
  6. 4 0
      app/Http/Controllers/Auth/WebAuthnRecoveryController.php
  7. 2 1
      app/Http/Middleware/SetLanguage.php
  8. 18 3
      app/Services/Auth/ReverseProxyGuard.php
  9. 5 76
      tests/Api/v1/Controllers/Auth/UserControllerTest.php
  10. 18 18
      tests/Api/v1/Controllers/GroupControllerTest.php
  11. 5 5
      tests/Api/v1/Controllers/QrCodeControllerTest.php
  12. 14 14
      tests/Api/v1/Controllers/SettingControllerTest.php
  13. 47 47
      tests/Api/v1/Controllers/TwoFAccountControllerTest.php
  14. 0 1
      tests/Feature/Console/ResetDemoTest.php
  15. 6 6
      tests/Feature/Http/Auth/ForgotPasswordControllerTest.php
  16. 4 9
      tests/Feature/Http/Auth/LoginTest.php
  17. 7 9
      tests/Feature/Http/Auth/PasswordControllerTest.php
  18. 3 3
      tests/Feature/Http/Auth/RegisterControllerTest.php
  19. 5 5
      tests/Feature/Http/Auth/ResetPasswordControllerTest.php
  20. 150 0
      tests/Feature/Http/Auth/UserControllerTest.php
  21. 67 0
      tests/Feature/Http/Auth/WebAuthnDeviceLostControllerTest.php
  22. 170 0
      tests/Feature/Http/Auth/WebAuthnManageControllerTest.php
  23. 115 0
      tests/Feature/Http/Auth/WebAuthnRecoveryControllerTest.php
  24. 224 0
      tests/Feature/Http/Auth/WebauthnLoginControllerTest.php
  25. 85 0
      tests/Feature/Http/Requests/UserDeleteRequestTest.php
  26. 5 2
      tests/Feature/Http/Requests/UserPatchPwdRequestTest.php
  27. 5 2
      tests/Feature/Http/Requests/UserStoreRequestTest.php
  28. 5 2
      tests/Feature/Http/Requests/UserUpdateRequestTest.php
  29. 85 0
      tests/Feature/Http/Requests/WebauthnRenameRequestTest.php
  30. 80 0
      tests/Feature/Middlewares/AuthenticateMiddlewareTest.php
  31. 2 2
      tests/Feature/Services/SettingServiceTest.php
  32. 0 4
      tests/Unit/Api/v1/Controllers/GroupControllerTest.php
  33. 26 0
      tests/Unit/Extensions/RemoteUserProviderTest.php
  34. 0 2
      tests/Unit/Listeners/DissociateTwofaccountFromGroupTest.php

+ 9 - 0
.env.testing

@@ -4,6 +4,15 @@ APP_KEY=base64:pdjaSqs7dDu8SdYCQzsayBAqeMC+85fmo3bpeBCCT94=
 APP_DEBUG=true
 APP_URL=http://localhost
 
+WEBAUTHN_NAME=2FAuth
+WEBAUTHN_ID=localhost
+WEBAUTHN_USER_VERIFICATION=discouraged
+
+AUTHENTICATION_GUARD=web-guard
+
+AUTH_PROXY_HEADER_FOR_USER=REMOTE_USER
+AUTH_PROXY_HEADER_FOR_EMAIL=REMOTE_USER_EMAIL
+
 LOG_CHANNEL=stack
 
 DB_CONNECTION=testing

+ 8 - 0
app/Extensions/RemoteUserProvider.php

@@ -36,6 +36,8 @@ class RemoteUserProvider implements UserProvider
 
     /**
      * @inheritDoc
+     * 
+     * @codeCoverageIgnore
      */
     public function retrieveByToken($identifier, $token)
     {
@@ -44,6 +46,8 @@ class RemoteUserProvider implements UserProvider
 
     /**
      * @inheritDoc
+     * 
+     * @codeCoverageIgnore
      */
     public function updateRememberToken(Authenticatable $user, $token)
     {
@@ -52,6 +56,8 @@ class RemoteUserProvider implements UserProvider
 
     /**
      * @inheritDoc
+     * 
+     * @codeCoverageIgnore
      */
     public function retrieveByCredentials(array $credentials)
     {
@@ -60,6 +66,8 @@ class RemoteUserProvider implements UserProvider
 
     /**
      * @inheritDoc
+     * 
+     * @codeCoverageIgnore
      */
     public function validateCredentials(Authenticatable $user, array $credentials)
     {

+ 2 - 0
app/Http/Controllers/Auth/UserController.php

@@ -93,9 +93,11 @@ class UserController extends Controller
             Artisan::call('passport:install --force');
             Artisan::call('config:clear');
         }
+        // @codeCoverageIgnoreStart
         catch (\Throwable $e) {
             return response()->json(['message' => __('errors.user_deletion_failed')], 400);
         }
+        // @codeCoverageIgnoreEnd
 
         return response()->json(null, 204);
     }

+ 0 - 15
app/Http/Controllers/Auth/WebAuthnDeviceLostController.php

@@ -47,19 +47,4 @@ class WebAuthnDeviceLostController extends Controller
     {
         return response()->json(['message' => __('auth.webauthn.account_recovery_email_sent')]);
     }
-
-
-    /**
-     * Get the response for a failed account recovery link.
-     *
-     * @param  \Illuminate\Http\Request  $request
-     * @param  string  $response
-     *
-     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
-     * @throws \Illuminate\Validation\ValidationException
-     */
-    protected function sendRecoveryLinkFailedResponse(Request $request, string $response)
-    {
-        throw ValidationException::withMessages(['email' => [trans($response)]]);
-    }
 }

+ 3 - 1
app/Http/Controllers/Auth/WebAuthnLoginController.php

@@ -30,7 +30,7 @@ class WebAuthnLoginController extends Controller
 	public function options(Request $request)
 	{
         // Since 2FAuth is single user designed we fetch the user instance
-        // and merge its email address to the request. This let Larapass validated
+        // and merge its email address to the request. This let Larapass validate
         // the request against a user instance without the need to ask the visitor
         // for an email address.
         //
@@ -57,6 +57,8 @@ class WebAuthnLoginController extends Controller
      */
     public function login(Request $request)
     {
+        $request->validate($this->assertionRules());
+
         if ($request->has('response')) {
             $response = $request->response;
 

+ 4 - 0
app/Http/Controllers/Auth/WebAuthnRecoveryController.php

@@ -59,6 +59,8 @@ class WebAuthnRecoveryController extends Controller
      * @param  string  $response
      *
      * @return \Illuminate\Http\JsonResponse
+     * 
+     * @codeCoverageIgnore - already covered by larapass test
      */
     protected function sendRecoveryResponse(Request $request, string $response): JsonResponse
     {
@@ -73,6 +75,8 @@ class WebAuthnRecoveryController extends Controller
      *
      * @return \Illuminate\Http\JsonResponse|void
      * @throws \Illuminate\Validation\ValidationException
+     * 
+     * @codeCoverageIgnore - already covered by larapass test
      */
     protected function sendRecoveryFailedResponse(Request $request, string $response): JsonResponse
     {

+ 2 - 1
app/Http/Middleware/SetLanguage.php

@@ -27,11 +27,12 @@ class SetLanguage
         $lang = SettingService::get('lang');
 
         if($lang === 'browser') {
+            $lang = config('app.fallback_locale');
+            
             if ($request->hasHeader("Accept-Language")) {
                 // We only keep the primary language passed via the header.
                 $lang = head(explode(',', $request->header("Accept-Language")));
             }
-            else $lang = config('app.fallback_locale');
         }
 
         // If the language is not available (or partial), strings will be translated using the fallback language.

+ 18 - 3
app/Services/Auth/ReverseProxyGuard.php

@@ -70,9 +70,15 @@ class ReverseProxyGuard implements Guard
 
         // Get the user identifier from $_SERVER or apache filtered headers
         $remoteUserHeader = config('auth.auth_proxy_headers.user', 'REMOTE_USER');
-        $identifier['user'] = request()->server($remoteUserHeader) ?? apache_request_headers()[$remoteUserHeader] ?? null;
 
-        if ($identifier['user'] === null) {
+        try {
+            $identifier['user'] = request()->server($remoteUserHeader) ?? apache_request_headers()[$remoteUserHeader] ?? null;
+        }
+        catch (\Throwable $e) {
+            $identifier['user'] = null;
+        }
+
+        if (! $identifier['user']) {
             Log::error(sprintf('No user in header "%s".', $remoteUserHeader));
             return $this->user = null;
         }
@@ -81,7 +87,12 @@ class ReverseProxyGuard implements Guard
         $remoteEmailHeader = config('auth.auth_proxy_headers.email');
 
         if ($remoteEmailHeader) {
-            $remoteEmail = (string)(request()->server($remoteEmailHeader) ?? apache_request_headers()[$remoteEmailHeader] ?? null);
+            try {
+                $remoteEmail = (string)(request()->server($remoteEmailHeader) ?? apache_request_headers()[$remoteEmailHeader] ?? null);
+            }
+            catch (\Throwable $e) {
+                $remoteEmail = null;
+            }
 
             if ($remoteEmail) {
                 $identifier['email'] = $remoteEmail;
@@ -95,6 +106,8 @@ class ReverseProxyGuard implements Guard
 
     /**
      * @inheritDoc
+     * 
+     * @codeCoverageIgnore
      */
     public function id()
     {
@@ -106,6 +119,8 @@ class ReverseProxyGuard implements Guard
      *
      * @param  array  $credentials
      * @return Exception
+     * 
+     * @codeCoverageIgnore
      */
     public function validate(array $credentials = [])
     {

+ 5 - 76
tests/Api/v1/Controllers/Auth/UserControllerTest.php

@@ -12,9 +12,6 @@ class UserControllerTest extends FeatureTestCase
     */
     protected $user;
 
-    private const NEW_USERNAME = 'Jane DOE';
-    private const NEW_EMAIL = 'janedoe@example.org';
-    private const PASSWORD =  'password';
 
     /**
      * @test
@@ -32,11 +29,12 @@ class UserControllerTest extends FeatureTestCase
      */
     public function test_show_existing_user_when_authenticated_returns_success()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/user')
             ->assertOk()
             ->assertExactJson([
                 'name'  => $this->user->name,
+                'id'    => $this->user->id,
                 'email' => $this->user->email,
             ]);
     }
@@ -62,83 +60,14 @@ class UserControllerTest extends FeatureTestCase
     {
         User::destroy($this->user->id);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->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\SettingService');
-        $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,
+                'name'  => $this->user->name,
+                'id'    => $this->user->id,
                 '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);
-    }
 
 }

+ 18 - 18
tests/Api/v1/Controllers/GroupControllerTest.php

@@ -38,7 +38,7 @@ class GroupControllerTest extends FeatureTestCase
     {
         Group::factory()->count(3)->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/groups')
             ->assertOk()
             ->assertJsonCount(4, $key = null)
@@ -62,7 +62,7 @@ class GroupControllerTest extends FeatureTestCase
      */
     public function test_store_returns_created_group_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/groups', [
                 'name' => 'My second group',
             ])
@@ -80,7 +80,7 @@ class GroupControllerTest extends FeatureTestCase
      */
     public function test_store_invalid_data_returns_validation_error()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/groups', [
                 'name' => null,
             ])
@@ -97,7 +97,7 @@ class GroupControllerTest extends FeatureTestCase
             'name' => 'My group',
         ]);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/groups/' . $group->id)
             ->assertOk()
             ->assertExactJson([
@@ -113,7 +113,7 @@ class GroupControllerTest extends FeatureTestCase
      */
     public function test_show_missing_group_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/groups/1000')
             ->assertNotFound()
             ->assertJsonStructure([
@@ -129,7 +129,7 @@ class GroupControllerTest extends FeatureTestCase
     {
         $group = Group::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/groups/' . $group->id, [
                 'name' => 'name updated',
             ])
@@ -147,7 +147,7 @@ class GroupControllerTest extends FeatureTestCase
      */
     public function test_update_missing_group_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/groups/1000', [
                 'name' => 'testUpdate',
             ])
@@ -165,7 +165,7 @@ class GroupControllerTest extends FeatureTestCase
     {
         $group = Group::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/groups/' . $group->id, [
                 'name' => null,
             ])
@@ -181,7 +181,7 @@ class GroupControllerTest extends FeatureTestCase
         $group = Group::factory()->create();
         $accounts = TwoFAccount::factory()->count(2)->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
                 'ids' => [1,2],
             ])
@@ -201,7 +201,7 @@ class GroupControllerTest extends FeatureTestCase
     {
         $accounts = TwoFAccount::factory()->count(2)->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/groups/1000/assign', [
                 'ids' => [1,2],
             ])
@@ -220,7 +220,7 @@ class GroupControllerTest extends FeatureTestCase
         $group = Group::factory()->create();
         $accounts = TwoFAccount::factory()->count(2)->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
                 'ids' => 1,
             ])
@@ -236,12 +236,12 @@ class GroupControllerTest extends FeatureTestCase
         $group = Group::factory()->create();
         $accounts = TwoFAccount::factory()->count(2)->create();
 
-        $assign = $this->actingAs($this->user, 'api')
+        $assign = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
                 'ids' => [1,2],
             ]);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/groups/' . $group->id . '/twofaccounts')
             ->assertOk()
             ->assertJsonCount(2)
@@ -269,12 +269,12 @@ class GroupControllerTest extends FeatureTestCase
         $group = Group::factory()->create();
         $accounts = TwoFAccount::factory()->count(2)->create();
 
-        $assign = $this->actingAs($this->user, 'api')
+        $assign = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
                 'ids' => [1,2],
             ]);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/groups/' . $group->id . '/twofaccounts?withSecret=1')
             ->assertOk()
             ->assertJsonCount(2)
@@ -300,7 +300,7 @@ class GroupControllerTest extends FeatureTestCase
      */
     public function test_get_assigned_accounts_of_missing_group_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/groups/1000/twofaccounts')
             ->assertNotFound()
             ->assertJsonStructure([
@@ -318,7 +318,7 @@ class GroupControllerTest extends FeatureTestCase
     {
         $group = Group::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('DELETE', '/api/v1/groups/' . $group->id)
             ->assertNoContent();
     }
@@ -331,7 +331,7 @@ class GroupControllerTest extends FeatureTestCase
      */
     public function test_destroy_missing_group_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('DELETE', '/api/v1/groups/1000')
             ->assertNotFound()
             ->assertJsonStructure([

+ 5 - 5
tests/Api/v1/Controllers/QrCodeControllerTest.php

@@ -47,7 +47,7 @@ class QrCodeControllerTest extends FeatureTestCase
             'legacy_uri' => 'otpauth://hotp/service:account?secret=A4GRFHZVRBGY7UIW&issuer=service',
         ]);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '/qrcode')
             ->assertJsonStructure([
                 'qrcode',
@@ -63,7 +63,7 @@ class QrCodeControllerTest extends FeatureTestCase
      */
     public function test_show_missing_qrcode_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/1000/qrcode')
             ->assertNotFound()
             ->assertJsonStructure([
@@ -80,7 +80,7 @@ class QrCodeControllerTest extends FeatureTestCase
         $file = LocalFile::fake()->validQrcode();
 
         $response = $this->withHeaders(['Content-Type' => 'multipart/form-data'])
-            ->actingAs($this->user, 'api')
+            ->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/qrcode/decode', [
                 'qrcode' => $file,
                 'inputFormat' => 'fileUpload'
@@ -97,7 +97,7 @@ class QrCodeControllerTest extends FeatureTestCase
      */
     public function test_decode_missing_qrcode_return_validation_error()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/qrcode/decode', [
                 'qrcode' => '',
             ])
@@ -113,7 +113,7 @@ class QrCodeControllerTest extends FeatureTestCase
         $file = LocalFile::fake()->invalidQrcode();
 
         $response = $this->withHeaders(['Content-Type' => 'multipart/form-data'])
-            ->actingAs($this->user, 'api')
+            ->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/qrcode/decode', [
                 'qrcode' => $file,
                 'inputFormat' => 'fileUpload'

+ 14 - 14
tests/Api/v1/Controllers/SettingControllerTest.php

@@ -45,7 +45,7 @@ class SettingControllerTest extends FeatureTestCase
      */
     public function test_index_returns_setting_collection()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/settings')
             ->assertOk()
             ->assertJsonStructure([
@@ -59,7 +59,7 @@ class SettingControllerTest extends FeatureTestCase
      */
     public function test_show_native_unchanged_setting_returns_consistent_value()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/settings/' . self::TWOFAUTH_NATIVE_SETTING)
             ->assertOk()
             ->assertExactJson([
@@ -77,7 +77,7 @@ class SettingControllerTest extends FeatureTestCase
         $settingService = resolve('App\Services\SettingService');
         $settingService->set(self::TWOFAUTH_NATIVE_SETTING, self::TWOFAUTH_NATIVE_SETTING_CHANGED_VALUE);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/settings/' . self::TWOFAUTH_NATIVE_SETTING)
             ->assertOk()
             ->assertExactJson([
@@ -95,7 +95,7 @@ class SettingControllerTest extends FeatureTestCase
         $settingService = resolve('App\Services\SettingService');
         $settingService->set(self::USER_DEFINED_SETTING, self::USER_DEFINED_SETTING_VALUE);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/settings/' . self::USER_DEFINED_SETTING)
             ->assertOk()
             ->assertExactJson([
@@ -110,7 +110,7 @@ class SettingControllerTest extends FeatureTestCase
      */
     public function test_show_missing_setting_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/settings/missing')
             ->assertNotFound();
     }
@@ -121,7 +121,7 @@ class SettingControllerTest extends FeatureTestCase
      */
     public function test_store_custom_user_setting_returns_success()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/settings', [
                 'key' => self::USER_DEFINED_SETTING,
                 'value' => self::USER_DEFINED_SETTING_VALUE,
@@ -139,7 +139,7 @@ class SettingControllerTest extends FeatureTestCase
      */
     public function test_store_invalid_custom_user_setting_returns_validation_error()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/settings', [
                 'key' => null,
                 'value' => null,
@@ -156,7 +156,7 @@ class SettingControllerTest extends FeatureTestCase
         $settingService = resolve('App\Services\SettingService');
         $settingService->set(self::USER_DEFINED_SETTING, self::USER_DEFINED_SETTING_VALUE);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/settings', [
                 'key' => self::USER_DEFINED_SETTING,
                 'value' => self::USER_DEFINED_SETTING_VALUE,
@@ -170,7 +170,7 @@ class SettingControllerTest extends FeatureTestCase
      */
     public function test_update_unchanged_native_setting_returns_updated_setting()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/settings/' . self::TWOFAUTH_NATIVE_SETTING, [
                 'value' => self::TWOFAUTH_NATIVE_SETTING_CHANGED_VALUE,
             ])
@@ -190,7 +190,7 @@ class SettingControllerTest extends FeatureTestCase
         $settingService = resolve('App\Services\SettingService');
         $settingService->set(self::USER_DEFINED_SETTING, self::USER_DEFINED_SETTING_VALUE);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/settings/' . self::USER_DEFINED_SETTING, [
                 'value' => self::USER_DEFINED_SETTING_CHANGED_VALUE,
             ])
@@ -207,7 +207,7 @@ class SettingControllerTest extends FeatureTestCase
      */
     public function test_update_missing_user_setting_returns_created_setting()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/settings/' . self::USER_DEFINED_SETTING, [
                 'value' => self::USER_DEFINED_SETTING_CHANGED_VALUE,
             ])
@@ -227,7 +227,7 @@ class SettingControllerTest extends FeatureTestCase
         $settingService = resolve('App\Services\SettingService');
         $settingService->set(self::USER_DEFINED_SETTING, self::USER_DEFINED_SETTING_VALUE);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('DELETE', '/api/v1/settings/' . self::USER_DEFINED_SETTING)
             ->assertNoContent();
     }
@@ -238,7 +238,7 @@ class SettingControllerTest extends FeatureTestCase
      */
     public function test_destroy_native_setting_returns_bad_request()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('DELETE', '/api/v1/settings/' . self::TWOFAUTH_NATIVE_SETTING)
             ->assertStatus(400)
             ->assertJsonStructure([
@@ -253,7 +253,7 @@ class SettingControllerTest extends FeatureTestCase
      */
     public function test_destroy_missing_user_setting_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('DELETE', '/api/v1/settings/' . self::USER_DEFINED_SETTING)
             ->assertNotFound();
     }

+ 47 - 47
tests/Api/v1/Controllers/TwoFAccountControllerTest.php

@@ -179,7 +179,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         TwoFAccount::factory()->count(3)->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts')
             ->assertOk()
             ->assertJsonCount(3, $key = null)
@@ -196,7 +196,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         TwoFAccount::factory()->count(3)->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts?withSecret=1')
             ->assertOk()
             ->assertJsonCount(3, $key = null)
@@ -213,7 +213,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $twofaccount = TwoFAccount::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id)
             ->assertOk()
             ->assertJsonStructure(self::VALID_RESOURCE_STRUCTURE_WITH_SECRET);
@@ -227,7 +227,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $twofaccount = TwoFAccount::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '?withSecret=0')
             ->assertOk()
             ->assertJsonStructure(self::VALID_RESOURCE_STRUCTURE_WITHOUT_SECRET);
@@ -251,7 +251,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     //             'account' => '**encrypted**',
     //         ]);
 
-    //     $response = $this->actingAs($this->user, 'api')
+    //     $response = $this->actingAs($this->user, 'api-guard')
     //         ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id)
     //         ->assertJsonFragment([
     //             'secret' => '*indecipherable*',
@@ -265,7 +265,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_show_missing_twofaccount_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/1000')
             ->assertNotFound()
             ->assertJsonStructure([
@@ -282,7 +282,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         Storage::put('test.png', 'emptied to prevent missing resource replaced by null by the model getter');
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', $data)
             ->assertCreated()
             ->assertJsonStructure(self::VALID_RESOURCE_STRUCTURE_WITH_SECRET);
@@ -328,7 +328,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_store_totp_using_fully_custom_uri_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', [
                 'uri' => self::TOTP_FULL_CUSTOM_URI,
             ])
@@ -341,7 +341,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_store_totp_using_short_uri_returns_resource_with_default_otp_parameter()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', [
                 'uri' => self::TOTP_SHORT_URI,
             ])
@@ -354,7 +354,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_store_totp_using_fully_custom_parameters_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP)
             ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP);
     }
@@ -365,7 +365,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_store_totp_using_minimum_parameters_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP)
             ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP);
     }
@@ -376,7 +376,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_store_hotp_using_fully_custom_uri_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', [
                 'uri' => self::HOTP_FULL_CUSTOM_URI,
             ])
@@ -389,7 +389,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_store_hotp_using_short_uri_returns_resource_with_default_otp_parameter()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', [
                 'uri' => self::HOTP_SHORT_URI,
             ])
@@ -402,7 +402,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_store_hotp_using_fully_custom_parameters_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP)
             ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP);
     }
@@ -413,7 +413,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_store_hotp_using_minimum_parameters_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_HOTP)
             ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_DEFAULT_HOTP);
     }
@@ -424,7 +424,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_store_with_invalid_uri_returns_validation_error()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', [
                 'uri' => self::INVALID_OTPAUTH_URI,
             ])
@@ -441,7 +441,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
         $settingService = resolve('App\Services\SettingService');
         $settingService->set('defaultGroup', $this->group->id);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', [
                 'uri' => self::TOTP_SHORT_URI,
             ])
@@ -463,7 +463,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
         // Set the active group
         $settingService->set('activeGroup', 1);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', [
                 'uri' => self::TOTP_SHORT_URI,
             ])
@@ -483,7 +483,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
         // Set the default group to No group
         $settingService->set('defaultGroup', 0);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', [
                 'uri' => self::TOTP_SHORT_URI,
             ])
@@ -503,7 +503,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
         // Set the default group to a non-existing one
         $settingService->set('defaultGroup', 1000);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts', [
                 'uri' => self::TOTP_SHORT_URI,
             ])
@@ -520,7 +520,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $twofaccount = TwoFAccount::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/twofaccounts/' . $twofaccount->id, self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP)
             ->assertOk()
             ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP);
@@ -534,7 +534,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $twofaccount = TwoFAccount::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/twofaccounts/' . $twofaccount->id, self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP)
             ->assertOk()
             ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP);
@@ -546,7 +546,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_update_missing_twofaccount_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/twofaccounts/1000', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP)
             ->assertNotFound();
     }
@@ -559,7 +559,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $twofaccount = TwoFAccount::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PUT', '/api/v1/twofaccounts/' . $twofaccount->id, self::ARRAY_OF_INVALID_PARAMETERS)
             ->assertStatus(422);
     }
@@ -572,7 +572,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         TwoFAccount::factory()->count(3)->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/reorder', [
                 'orderedIds' => [3,2,1]])
             ->assertStatus(200)
@@ -589,7 +589,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         TwoFAccount::factory()->count(3)->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/reorder', [
                 'orderedIds' => '3,2,1'])
             ->assertStatus(422);
@@ -601,7 +601,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_preview_returns_success_with_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/preview', [
                 'uri' => self::TOTP_FULL_CUSTOM_URI,
             ])
@@ -615,7 +615,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_preview_with_invalid_data_returns_validation_error()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/preview', [
                 'uri' => self::INVALID_OTPAUTH_URI,
             ])
@@ -628,7 +628,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_preview_with_unreachable_image_returns_success()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/preview', [
                 'uri' => self::TOTP_URI_WITH_UNREACHABLE_IMAGE,
             ])
@@ -656,7 +656,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
             'icon' => '',
         ]);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '/otp')
             ->assertOk()
             ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_TOTP)
@@ -672,7 +672,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_get_otp_by_posting_totp_uri_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/otp', [
                 'uri' => self::TOTP_FULL_CUSTOM_URI,
             ])
@@ -690,7 +690,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_get_otp_by_posting_totp_parameters_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/otp', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP)
             ->assertOk()
             ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_TOTP)
@@ -718,7 +718,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
             'icon' => '',
         ]);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '/otp')
             ->assertOk()
             ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_HOTP)
@@ -734,7 +734,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_get_otp_by_posting_hotp_uri_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/otp', [
                 'uri' => self::HOTP_FULL_CUSTOM_URI,
             ])
@@ -752,7 +752,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_get_otp_by_posting_hotp_parameters_returns_consistent_resource()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/otp', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP)
             ->assertOk()
             ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_HOTP)
@@ -768,7 +768,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_get_otp_by_posting_multiple_inputs_returns_bad_request()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/otp', [
                 'uri' => self::HOTP_FULL_CUSTOM_URI,
                 'key' => 'value',
@@ -797,7 +797,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
                 'secret' => '**encrypted**',
             ]);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '/otp')
             ->assertStatus(400)
             ->assertJsonStructure([
@@ -811,7 +811,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_get_otp_using_missing_twofaccount_id_returns_not_found()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/1000/otp')
             ->assertNotFound();
     }
@@ -822,7 +822,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_get_otp_by_posting_invalid_uri_returns_validation_error()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/otp', [
                 'uri' => self::INVALID_OTPAUTH_URI,
             ])
@@ -835,7 +835,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_get_otp_by_posting_invalid_parameters_returns_validation_error()
     {
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('POST', '/api/v1/twofaccounts/otp', self::ARRAY_OF_INVALID_PARAMETERS)
             ->assertStatus(422);
     }
@@ -848,7 +848,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         TwoFAccount::factory()->count(3)->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts/count')
             ->assertStatus(200)
             ->assertExactJson([
@@ -865,7 +865,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
         TwoFAccount::factory()->count(3)->create();
         $ids = DB::table('twofaccounts')->pluck('id')->implode(',');
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PATCH', '/api/v1/twofaccounts/withdraw?ids=1,2,3' . $ids)
             ->assertOk()
             ->assertJsonStructure([
@@ -882,7 +882,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
         TwoFAccount::factory()->count(102)->create();
         $ids = DB::table('twofaccounts')->pluck('id')->implode(',');
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('PATCH', '/api/v1/twofaccounts/withdraw?ids=' . $ids)
             ->assertStatus(400)
             ->assertJsonStructure([
@@ -899,7 +899,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $twofaccount = TwoFAccount::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('DELETE', '/api/v1/twofaccounts/' . $twofaccount->id)
             ->assertNoContent();
     }
@@ -912,7 +912,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $twofaccount = TwoFAccount::factory()->create();
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('DELETE', '/api/v1/twofaccounts/1000')
             ->assertNotFound();
     }
@@ -926,7 +926,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
         TwoFAccount::factory()->count(3)->create();
         $ids = DB::table('twofaccounts')->pluck('id')->implode(',');
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('DELETE', '/api/v1/twofaccounts?ids=' . $ids)
             ->assertNoContent();
     }
@@ -940,7 +940,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
         TwoFAccount::factory()->count(102)->create();
         $ids = DB::table('twofaccounts')->pluck('id')->implode(',');
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('DELETE', '/api/v1/twofaccounts?ids=' . $ids)
             ->assertStatus(400)
             ->assertJsonStructure([

+ 0 - 1
tests/Feature/Console/ResetDemoTest.php

@@ -5,7 +5,6 @@ namespace Tests\Feature\Console;
 use App\Models\User;
 use Tests\FeatureTestCase;
 use Illuminate\Support\Facades\Config;
-use Illuminate\Support\Facades\DB;
 
 class ResetDemoTest extends FeatureTestCase
 {

+ 6 - 6
tests/Api/v1/Controllers/Auth/ForgotPasswordControllerTest.php → tests/Feature/Http/Auth/ForgotPasswordControllerTest.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace Tests\Api\v1\Controllers\Auth;
+namespace Tests\Feature\Auth;
 
 use App\Models\User;
 use Illuminate\Support\Facades\Hash;
@@ -21,7 +21,7 @@ class ForgotPasswordControllerTest extends FeatureTestCase
      */
     public function test_submit_email_password_request_without_email_returns_validation_error()
     {
-        $response = $this->json('POST', '/api/v1/user/password/lost', [
+        $response = $this->json('POST', '/user/password/lost', [
             'email' => ''
         ]);
 
@@ -34,7 +34,7 @@ class ForgotPasswordControllerTest extends FeatureTestCase
      */
     public function test_submit_email_password_request_with_invalid_email_returns_validation_error()
     {
-        $response = $this->json('POST', '/api/v1/user/password/lost', [
+        $response = $this->json('POST', '/user/password/lost', [
             'email' => 'nametest.com'
         ]);
 
@@ -47,7 +47,7 @@ class ForgotPasswordControllerTest extends FeatureTestCase
      */
     public function test_submit_email_password_request_with_unknown_email_returns_validation_error()
     {
-        $response = $this->json('POST', '/api/v1/user/password/lost', [
+        $response = $this->json('POST', '/user/password/lost', [
             'email' => 'name@test.com'
         ]);
 
@@ -64,7 +64,7 @@ class ForgotPasswordControllerTest extends FeatureTestCase
 
         $this->user = User::factory()->create();
 
-        $response = $this->json('POST', '/api/v1/user/password/lost', [
+        $response = $this->json('POST', '/user/password/lost', [
             'email' => $this->user->email
         ]);
 
@@ -85,7 +85,7 @@ class ForgotPasswordControllerTest extends FeatureTestCase
     {
         Config::set('2fauth.config.isDemoApp', true);
 
-        $response = $this->json('POST', '/api/v1/user/password/lost', [
+        $response = $this->json('POST', '/user/password/lost', [
             'email' => ''
         ]);
 

+ 4 - 9
tests/Feature/Auth/LoginTest.php → tests/Feature/Http/Auth/LoginTest.php

@@ -4,11 +4,6 @@ namespace Tests\Feature\Auth;
 
 use App\Models\User;
 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 FeatureTestCase
 {
@@ -58,7 +53,7 @@ class LoginTest extends FeatureTestCase
             'password' => self::PASSWORD
         ]);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'web-guard')
             ->json('POST', '/user/login', [
                 'email' => $this->user->email,
                 'password' => self::PASSWORD
@@ -152,7 +147,7 @@ class LoginTest extends FeatureTestCase
             'password' => self::PASSWORD
         ]);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'web-guard')
             ->json('GET', '/user/logout')
             ->assertOk()
             ->assertExactJson([
@@ -176,12 +171,12 @@ class LoginTest extends FeatureTestCase
         ]);
 
         // Ping a protected endpoint to log last_seen_at time
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts');
 
         sleep(61);
 
-        $response = $this->actingAs($this->user, 'api')
+        $response = $this->actingAs($this->user, 'api-guard')
             ->json('GET', '/api/v1/twofaccounts')
             ->assertUnauthorized();
     }

+ 7 - 9
tests/Api/v1/Controllers/Auth/PasswordControllerTest.php → tests/Feature/Http/Auth/PasswordControllerTest.php

@@ -1,11 +1,9 @@
 <?php
 
-namespace Tests\Api\v1\Controllers\Auth;
+namespace Tests\Feature\Auth;
 
 use App\Models\User;
-use App\Models\Group;
 use Tests\FeatureTestCase;
-use App\Models\TwoFAccount;
 
 class PasswordControllerTest extends FeatureTestCase
 {
@@ -33,8 +31,8 @@ class PasswordControllerTest extends FeatureTestCase
      */
     public function test_update_return_success()
     {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('PATCH', '/api/v1/user/password', [
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('PATCH', '/user/password', [
                 'currentPassword' => self::PASSWORD,
                 'password' => self::NEW_PASSWORD,
                 'password_confirmation' => self::NEW_PASSWORD,
@@ -51,8 +49,8 @@ class PasswordControllerTest extends FeatureTestCase
      */
     public function test_update_passing_bad_current_pwd_return_bad_request()
     {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('PATCH', '/api/v1/user/password', [
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('PATCH', '/user/password', [
                 'currentPassword' => self::NEW_PASSWORD,
                 'password' => self::NEW_PASSWORD,
                 'password_confirmation' => self::NEW_PASSWORD,
@@ -69,8 +67,8 @@ class PasswordControllerTest extends FeatureTestCase
      */
     public function test_update_passing_invalid_data_return_validation_error()
     {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('PATCH', '/api/v1/user/password', [
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('PATCH', '/user/password', [
                 'currentPassword' => self::PASSWORD,
                 'password' => null,
                 'password_confirmation' => self::NEW_PASSWORD,

+ 3 - 3
tests/Api/v1/Controllers/Auth/RegisterControllerTest.php → tests/Feature/Http/Auth/RegisterControllerTest.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace Tests\Api\v1\Controllers\Auth;
+namespace Tests\Feature\Auth;
 
 use Tests\FeatureTestCase;
 
@@ -25,7 +25,7 @@ class RegisterControllerTest extends FeatureTestCase
      */
     public function test_register_returns_success()
     {
-        $response = $this->json('POST', '/api/v1/user', [
+        $response = $this->json('POST', '/user', [
                 'name' => self::USERNAME,
                 'email' => self::EMAIL,
                 'password' => self::PASSWORD,
@@ -47,7 +47,7 @@ class RegisterControllerTest extends FeatureTestCase
      */
     public function test_register_with_invalid_data_returns_validation_error()
     {
-        $response = $this->json('POST', '/api/v1/user', [
+        $response = $this->json('POST', '/user', [
                 'name' => null,
                 'email' => self::EMAIL,
                 'password' => self::PASSWORD,

+ 5 - 5
tests/Api/v1/Controllers/Auth/ResetPasswordControllerTest.php → tests/Feature/Http/Auth/ResetPasswordControllerTest.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace Tests\Api\v1\Controllers\Auth;
+namespace Tests\Feature\Auth;
 
 use App\Models\User;
 use Illuminate\Support\Facades\Hash;
@@ -21,7 +21,7 @@ class ResetPasswordControllerTest extends FeatureTestCase
      */
     public function test_submit_reset_password_without_input_returns_validation_error()
     {
-        $response = $this->json('POST', '/api/v1/user/password/reset', [
+        $response = $this->json('POST', '/user/password/reset', [
             'email' => '',
             'password' => '',
             'password_confirmation' => '',
@@ -37,7 +37,7 @@ class ResetPasswordControllerTest extends FeatureTestCase
      */
     public function test_submit_reset_password_with_invalid_data_returns_validation_error()
     {
-        $response = $this->json('POST', '/api/v1/user/password/reset', [
+        $response = $this->json('POST', '/user/password/reset', [
             'email' => 'qsdqsdqsd',
             'password' => 'foofoofoo',
             'password_confirmation' => 'barbarbar',
@@ -53,7 +53,7 @@ class ResetPasswordControllerTest extends FeatureTestCase
      */
     public function test_submit_reset_password_with_too_short_pwd_returns_validation_error()
     {
-        $response = $this->json('POST', '/api/v1/user/password/reset', [
+        $response = $this->json('POST', '/user/password/reset', [
             'email' => 'foo@bar.com',
             'password' => 'foo',
             'password_confirmation' => 'foo',
@@ -74,7 +74,7 @@ class ResetPasswordControllerTest extends FeatureTestCase
         $this->user = User::factory()->create();
         $token = Password::broker()->createToken($this->user);
 
-        $response = $this->json('POST', '/api/v1/user/password/reset', [
+        $response = $this->json('POST', '/user/password/reset', [
             'email' => $this->user->email,
             'password' => 'newpassword',
             'password_confirmation' => 'newpassword',

+ 150 - 0
tests/Feature/Http/Auth/UserControllerTest.php

@@ -0,0 +1,150 @@
+<?php
+
+namespace Tests\Feature\Auth;
+
+use App\Models\User;
+use Tests\FeatureTestCase;
+use Illuminate\Support\Facades\Config;
+
+class UserControllerTest extends FeatureTestCase
+{
+    /**
+     * @var \App\Models\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 = User::factory()->create();
+    }
+    
+
+    /**
+     * @test
+     */
+    public function test_update_user_returns_success()
+    {
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('PUT', '/user', [
+                'name' => self::NEW_USERNAME,
+                'email' => self::NEW_EMAIL,
+                'password' => self::PASSWORD,
+            ])
+            ->assertOk()
+            ->assertExactJson([
+                'name' => self::NEW_USERNAME,
+                'id'    => $this->user->id,
+                'email' => self::NEW_EMAIL,
+            ]);
+    }
+    
+
+    /**
+     * @test
+     */
+    public function test_update_user_in_demo_mode_returns_unchanged_user()
+    {
+        $settingService = resolve('App\Services\SettingService');
+        $settingService->set('isDemoApp', true);
+
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('PUT', '/user', [
+                'name' => self::NEW_USERNAME,
+                'email' => self::NEW_EMAIL,
+                'password' => self::PASSWORD,
+            ])
+            ->assertOk()
+            ->assertExactJson([
+                'name' => $this->user->name,
+                'id'    => $this->user->id,
+                'email' => $this->user->email,
+            ]);
+    }
+    
+
+    /**
+     * @test
+     */
+    public function test_update_user_passing_wrong_password_returns_bad_request()
+    {
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('PUT', '/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, 'web-guard')
+            ->json('PUT', '/user', [
+                'name' => '',
+                'email' => '',
+                'password' => self::PASSWORD,
+            ])
+            ->assertStatus(422);
+    }
+    
+
+    /**
+     * @test
+     */
+    public function test_delete_user_returns_success()
+    {
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('DELETE', '/user', [
+                'password' => self::PASSWORD,
+            ])
+            ->assertNoContent();
+    }
+    
+
+    /**
+     * @test
+     */
+    public function test_delete_user_in_demo_mode_returns_unauthorized()
+    {
+        Config::set('2fauth.config.isDemoApp', true);
+
+        $settingService = resolve('App\Services\SettingService');
+        $settingService->set('isDemoApp', true);
+
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('DELETE', '/user', [
+                'password' => self::PASSWORD,
+            ])
+            ->assertUnauthorized()
+            ->assertJsonStructure([
+                'message'
+            ]);
+    }
+    
+
+    /**
+     * @test
+     */
+    public function test_delete_user_passing_wrong_password_returns_bad_request()
+    {
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('DELETE', '/user', [
+                'password' => 'wrongPassword',
+            ])
+            ->assertStatus(400);
+    }
+
+}

+ 67 - 0
tests/Feature/Http/Auth/WebAuthnDeviceLostControllerTest.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace Tests\Feature\Auth;
+
+use App\Models\User;
+use Tests\FeatureTestCase;
+use Illuminate\Support\Facades\Notification;
+
+class WebAuthnDeviceLostControllerTest extends FeatureTestCase
+{
+    /**
+     * @var \App\Models\User
+    */
+    protected $user;
+
+
+    /**
+     * @test
+     */
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->user = User::factory()->create();
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_sendRecoveryEmail_sends_notification_on_success()
+    {
+        Notification::fake();
+
+        $response = $this->json('POST', '/webauthn/lost', [
+            'email' => $this->user->email,
+        ]);
+
+        Notification::assertSentTo($this->user, \DarkGhostHunter\Larapass\Notifications\AccountRecoveryNotification::class);
+
+        $response->assertStatus(200)
+        ->assertJsonStructure([
+            'message'
+        ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_sendRecoveryEmail_does_not_send_anything_on_error()
+    {
+        Notification::fake();
+
+        $response = $this->json('POST', '/webauthn/lost', [
+            'email' => 'bad@email.com',
+        ]);
+
+        Notification::assertNothingSent();
+
+        $response->assertStatus(422)
+        ->assertJsonValidationErrors([
+            'email'
+        ]);
+    }
+
+}

+ 170 - 0
tests/Feature/Http/Auth/WebAuthnManageControllerTest.php

@@ -0,0 +1,170 @@
+<?php
+
+namespace Tests\Feature\Auth;
+
+use App\Models\User;
+use Tests\FeatureTestCase;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Str;
+use Webauthn\TrustPath\EmptyTrustPath;
+
+class WebAuthnManageControllerTest extends FeatureTestCase
+{
+    /**
+     * @var \App\Models\User
+    */
+    protected $user;
+
+
+    /**
+     * @test
+     */
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->user = User::factory()->create();
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_index_returns_success_with_credentials()
+    {
+        DB::table('web_authn_credentials')->insert([
+            'id'               => 'test_credential_id',
+            'user_id'          => $this->user->id,
+            'type'             => 'public_key',
+            'transports'       => json_encode([]),
+            'attestation_type' => 'none',
+            'trust_path'       => json_encode(['type' => EmptyTrustPath::class]),
+            'aaguid'           => Str::uuid(),
+            'public_key'       => 'public_key_bar',
+            'counter'          => 0,
+            'user_handle'      => 'test_id',
+            'created_at'       => now()->toDateTimeString(),
+            'updated_at'       => now()->toDateTimeString(),
+            'disabled_at'      => null,
+        ]);
+
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('GET', '/webauthn/credentials')
+            ->assertStatus(200)
+            ->assertJsonStructure([
+                '*' => [
+                    'id',
+                    'name',
+                    'type',
+                    'transports'
+                ]
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_rename_returns_success_with_new_name()
+    {
+        DB::table('web_authn_credentials')->insert([
+            'id'               => 'test_credential_id',
+            'name'             => 'MyCredential',
+            'user_id'          => $this->user->id,
+            'type'             => 'public_key',
+            'transports'       => json_encode([]),
+            'attestation_type' => 'none',
+            'trust_path'       => json_encode(['type' => EmptyTrustPath::class]),
+            'aaguid'           => Str::uuid(),
+            'public_key'       => 'public_key_bar',
+            'counter'          => 0,
+            'user_handle'      => 'test_id',
+            'created_at'       => now()->toDateTimeString(),
+            'updated_at'       => now()->toDateTimeString(),
+            'disabled_at'      => null,
+        ]);
+
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('PATCH', '/webauthn/credentials/test_credential_id/name',[
+                'name' => 'MyNewCredential',
+            ])
+            ->assertStatus(200)
+            ->assertExactJson([
+                'name' => 'MyNewCredential',
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_rename_invalid_data_returns_validation_error()
+    {
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('PATCH', '/webauthn/credentials/test_credential_id/name', [
+                'name' => null,
+            ])
+            ->assertStatus(422);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_rename_missing_credential_returns_not_found()
+    {
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('PATCH', '/webauthn/credentials/unknown/name', [
+                'name' => 'MyNewCredential',
+            ])
+            ->assertNotFound()
+            ->assertJsonStructure([
+                'message'
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_index_as_reverse_proxy_returns_error()
+    {
+        $response = $this->actingAs($this->user, 'reverse-proxy-guard')
+            ->json('GET', '/webauthn/credentials')
+            ->assertStatus(400);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_rename_as_reverse_proxy_returns_error()
+    {
+        $response = $this->actingAs($this->user, 'reverse-proxy-guard')
+            ->json('PATCH', '/webauthn/credentials/fqsdfqsdf/name')
+            ->assertStatus(400);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_delete_as_reverse_proxy_returns_error()
+    {
+        $response = $this->actingAs($this->user, 'reverse-proxy-guard')
+            ->json('DELETE', '/webauthn/credentials/dcnskldjnkljsrn')
+            ->assertStatus(400);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_delete_returns_no_content()
+    {
+        $response = $this->actingAs($this->user, 'web-guard')
+            ->json('DELETE', '/webauthn/credentials/sdCKktnsdK')
+            ->assertNoContent();
+    }
+
+}

+ 115 - 0
tests/Feature/Http/Auth/WebAuthnRecoveryControllerTest.php

@@ -0,0 +1,115 @@
+<?php
+
+namespace Tests\Feature\Auth;
+
+use App\Models\User;
+use Tests\FeatureTestCase;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Date;
+
+class WebAuthnRecoveryControllerTest extends FeatureTestCase
+{
+    /**
+     * @var \App\Models\User
+    */
+    protected $user;
+    
+
+    /**
+     * @test
+     */
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->user = User::factory()->create();
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_options_returns_success()
+    {
+        $token = '$2y$10$hgGTVVTRLsSYSlAHpyydBu6m4ZuRheBqTTUfRE/aG89DaqEyo.HPu';
+        Date::setTestNow($now = Date::create(2020, 01, 01, 16, 30));
+
+        DB::table('web_authn_recoveries')->insert([
+            'email'      => $this->user->email,
+            'token'      => $token,
+            'created_at' => $now->toDateTimeString(),
+        ]);
+
+        $response = $this->json('POST', '/webauthn/recover/options', [
+            'token' => 'test_token',
+            'email' => $this->user->email,
+        ])
+        ->assertStatus(200);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_options_with_invalid_token_returns_error()
+    {
+        $response = $this->json('POST', '/webauthn/recover/options', [
+            'token' => 'myToken',
+            'email' => $this->user->email,
+        ])
+        ->assertStatus(401);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_options_without_inputs_returns_validation_errors()
+    {
+        $response = $this->json('POST', '/webauthn/recover/options', [
+            'token' => '',
+            'email' => '',
+        ]);
+
+        $response->assertStatus(422)
+            ->assertJsonValidationErrors(['token'])
+            ->assertJsonValidationErrors(['email']);
+    }
+
+
+    /**
+     * @test
+     */
+    // public function test_recover_returns_success()
+    // {
+    //     $token = '$2y$10$hgGTVVTRLsSYSlAHpyydBu6m4ZuRheBqTTUfRE/aG89DaqEyo.HPu';
+    //     Date::setTestNow($now = Date::create(2020, 01, 01, 16, 30));
+
+    //     DB::table('web_authn_recoveries')->insert([
+    //         'email'      => $this->user->email,
+    //         'token'      => $token,
+    //         'created_at' => $now->toDateTimeString(),
+    //     ]);
+
+    //     $response = $this->json('POST', '/webauthn/recover', [], [
+    //         'token' => $token,
+    //         'email' => $this->user->email,
+    //     ])
+    //     ->assertStatus(200);
+    // }
+
+
+    /**
+     * @test
+     */
+    public function test_recover_with_invalid_token_returns_validation_error()
+    {
+        $response = $this->json('POST', '/webauthn/recover', [], [
+            'token' => 'toekn',
+            'email' => $this->user->email,
+        ])
+        ->assertStatus(422)
+        ->assertJsonValidationErrors(['email']);
+    }
+
+}

+ 224 - 0
tests/Feature/Http/Auth/WebauthnLoginControllerTest.php

@@ -0,0 +1,224 @@
+<?php
+
+namespace Tests\Feature\Auth;
+
+use App\Models\User;
+use Tests\FeatureTestCase;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Str;
+use Webauthn\TrustPath\EmptyTrustPath;
+use DarkGhostHunter\Larapass\Eloquent\WebAuthnCredential;
+use DarkGhostHunter\Larapass\WebAuthn\WebAuthnAssertValidator;
+
+class WebAuthnLoginControllerTest extends FeatureTestCase
+{
+    /**
+     * @var \App\Models\User
+    */
+    protected $user;
+
+
+    /**
+     * @test
+     */
+    public function setUp(): void
+    {
+        parent::setUp();
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_user_login_returns_success()
+    {
+        $this->user = User::factory()->create([
+            'name'     => 'john',
+            'email'    => 'john.doe@mail.com',
+            'password' => '$2y$10$FLIykVJWDsYSVMJyaFZZfe4tF5uBTnGsosJBL.ZfAAHsYgc27FSdi',
+        ]);
+        $uuid = Str::uuid();
+
+        DB::table('web_authn_credentials')->insert([
+            'id'               => 'dGVzdF9jcmVkZW50aWFsX2lk',
+            'user_id'          => 1,
+            'type'             => 'public_key',
+            'transports'       => json_encode([]),
+            'attestation_type' => 'none',
+            'trust_path'       => json_encode(['type' => EmptyTrustPath::class]),
+            'aaguid'           => $uuid->toString(),
+            'public_key'       => 'public_key',
+            'counter'          => 0,
+            'user_handle'      => 'test_user_handle',
+            'created_at'       => now()->toDateTimeString(),
+            'updated_at'       => now()->toDateTimeString(),
+        ]);
+
+        $data = [
+            'id'       => 'dGVzdF9jcmVkZW50aWFsX2lk',
+            'rawId'    => 'ZEdWemRGOWpjbVZrWlc1MGFXRnNYMmxr',
+            'type'     => 'test_type',
+            'response' => [
+                'authenticatorData' => 'test',
+                'clientDataJSON' => 'test',
+                'signature' => 'test',
+                'userHandle' => 'test',
+            ],
+        ];
+
+        $this->mock(WebAuthnAssertValidator::class)
+            ->shouldReceive('validate')
+            ->with($data)
+            ->andReturnUsing(function ($data) {
+                $credentials = WebAuthnCredential::find($data['id']);
+
+                $credentials->setAttribute('counter', 1)->save();
+
+                return $credentials->toCredentialSource();
+            });
+
+        $this->json('POST', '/webauthn/login', $data)
+            ->assertNoContent();
+
+        $this->assertAuthenticatedAs($this->user);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_user_login_without_userhandle_returns_success()
+    {
+        $this->user = User::factory()->create([
+            'name'     => 'john',
+            'email'    => 'john.doe@mail.com',
+            'password' => '$2y$10$FLIykVJWDsYSVMJyaFZZfe4tF5uBTnGsosJBL.ZfAAHsYgc27FSdi',
+        ]);
+        $uuid = Str::uuid();
+
+        DB::table('web_authn_credentials')->insert([
+            'id'               => 'dGVzdF9jcmVkZW50aWFsX2lk',
+            'user_id'          => 1,
+            'type'             => 'public_key',
+            'transports'       => json_encode([]),
+            'attestation_type' => 'none',
+            'trust_path'       => json_encode(['type' => EmptyTrustPath::class]),
+            'aaguid'           => $uuid->toString(),
+            'public_key'       => 'public_key',
+            'counter'          => 0,
+            'user_handle'      => 'test_user_handle',
+            'created_at'       => now()->toDateTimeString(),
+            'updated_at'       => now()->toDateTimeString(),
+        ]);
+
+        $data = [
+            'id'       => 'dGVzdF9jcmVkZW50aWFsX2lk',
+            'rawId'    => 'ZEdWemRGOWpjbVZrWlc1MGFXRnNYMmxr',
+            'type'     => 'test_type',
+            'response' => [
+                'authenticatorData' => 'test',
+                'clientDataJSON' => 'test',
+                'signature' => 'test',
+                'userHandle' => '',
+            ],
+        ];
+
+        $this->mock(WebAuthnAssertValidator::class)
+            ->shouldReceive('validate')
+            ->with([
+                'id'       => 'dGVzdF9jcmVkZW50aWFsX2lk',
+                'rawId'    => 'ZEdWemRGOWpjbVZrWlc1MGFXRnNYMmxr',
+                'type'     => 'test_type',
+                'response' => [
+                    'authenticatorData' => 'test',
+                    'clientDataJSON' => 'test',
+                    'signature' => 'test',
+                    'userHandle' => 'dGVzdF91c2VyX2hhbmRsZQ==',
+                ],
+            ])
+            ->andReturnUsing(function ($data) {
+                $credentials = WebAuthnCredential::find($data['id']);
+
+                $credentials->setAttribute('counter', 1)->save();
+
+                return $credentials->toCredentialSource();
+            });
+
+        $this->json('POST', '/webauthn/login', $data)
+            ->assertNoContent();
+
+        $this->assertAuthenticatedAs($this->user);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_user_login_with_missing_data_returns_validation_error()
+    {
+        $this->user = User::factory()->create([
+            'name'     => 'john',
+            'email'    => 'john.doe@mail.com',
+            'password' => '$2y$10$FLIykVJWDsYSVMJyaFZZfe4tF5uBTnGsosJBL.ZfAAHsYgc27FSdi',
+        ]);
+
+        $data = [
+            'id'       => '',
+            'rawId'    => '',
+            'type'     => '',
+            'response' => [
+                'authenticatorData' => '',
+                'clientDataJSON' => '',
+                'signature' => '',
+                'userHandle' => null,
+            ],
+        ];
+
+        $response = $this->json('POST', '/webauthn/login', $data)
+        ->assertStatus(422)
+        ->assertJsonValidationErrors([
+            'id',
+            'rawId',
+            'type',
+            'response.authenticatorData',
+            'response.clientDataJSON',
+            'response.signature',
+        ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_get_options_returns_success()
+    {
+        $this->user = User::factory()->create([
+            'name'     => 'john',
+            'email'    => 'john.doe@mail.com',
+            'password' => '$2y$10$FLIykVJWDsYSVMJyaFZZfe4tF5uBTnGsosJBL.ZfAAHsYgc27FSdi',
+        ]);
+
+        $response = $this->json('POST', '/webauthn/login/options', [])
+        ->assertOk()
+        ->assertJsonStructure([
+            'challenge',
+            'rpId',
+            'userVerification',
+            'timeout',
+        ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_get_options_with_no_registred_user_returns_error()
+    {
+        $this->json('POST', '/webauthn/login/options', [])
+        ->assertStatus(400)
+        ->assertJsonStructure([
+            'message',
+        ]);
+    }
+
+}

+ 85 - 0
tests/Feature/Http/Requests/UserDeleteRequestTest.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace Tests\Feature\Http\Requests;
+
+use App\Http\Requests\UserDeleteRequest;
+use Illuminate\Foundation\Testing\WithoutMiddleware;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Validator;
+use Tests\FeatureTestCase;
+
+/**
+ * @covers \App\Http\Requests\UserDeleteRequest
+ */
+class UserDeleteRequestTest extends FeatureTestCase
+{
+
+    use WithoutMiddleware;
+
+    /**
+     * @test
+     */
+    public function test_user_is_authorized()
+    {
+        Auth::shouldReceive('check')
+        ->once()
+        ->andReturn(true);
+
+        $request = new UserDeleteRequest();
+    
+        $this->assertTrue($request->authorize());
+    }
+
+    /**
+     * @dataProvider provideValidData
+     */
+    public function test_valid_data(array $data) : void
+    {
+        $request = new UserDeleteRequest();
+        $validator = Validator::make($data, $request->rules());
+
+        $this->assertFalse($validator->fails());
+    }
+
+    /**
+     * Provide Valid data for validation test
+     */
+    public function provideValidData() : array
+    {
+        return [
+            [[
+                'password'  => 'Yubikey',
+            ]],
+        ];
+    }
+
+    /**
+     * @dataProvider provideInvalidData
+     */
+    public function test_invalid_data(array $data) : void
+    {        
+        $request = new UserDeleteRequest();
+        $validator = Validator::make($data, $request->rules());
+
+        $this->assertTrue($validator->fails());
+    }
+
+    /**
+     * Provide invalid data for validation test
+     */
+    public function provideInvalidData() : array
+    {
+        return [
+            [[
+                'password'  => '', // required
+            ]],
+            [[
+                'password'  => true, // string
+            ]],
+            [[
+                'password'  => 0, // string
+            ]],
+        ];
+    }
+
+}

+ 5 - 2
tests/Api/v1/Requests/UserPatchPwdRequestTest.php → tests/Feature/Http/Requests/UserPatchPwdRequestTest.php

@@ -1,13 +1,16 @@
 <?php
 
-namespace Tests\Api\v1\Requests;
+namespace Tests\Feature\Http\Requests;
 
-use App\Api\v1\Requests\UserPatchPwdRequest;
+use App\Http\Requests\UserPatchPwdRequest;
 use Illuminate\Foundation\Testing\WithoutMiddleware;
 use Illuminate\Support\Facades\Validator;
 use Illuminate\Support\Facades\Auth;
 use Tests\TestCase;
 
+/**
+ * @covers \App\Http\Requests\UserPatchPwdRequest
+ */
 class UserPatchPwdRequestTest extends TestCase
 {
 

+ 5 - 2
tests/Api/v1/Requests/UserStoreRequestTest.php → tests/Feature/Http/Requests/UserStoreRequestTest.php

@@ -1,12 +1,15 @@
 <?php
 
-namespace Tests\Api\v1\Requests;
+namespace Tests\Feature\Http\Requests;
 
-use App\Api\v1\Requests\UserStoreRequest;
+use App\Http\Requests\UserStoreRequest;
 use Illuminate\Foundation\Testing\WithoutMiddleware;
 use Illuminate\Support\Facades\Validator;
 use Tests\FeatureTestCase;
 
+/**
+ * @covers \App\Http\Requests\UserStoreRequest
+ */
 class UserStoreRequestTest extends FeatureTestCase
 {
 

+ 5 - 2
tests/Api/v1/Requests/UserUpdateRequestTest.php → tests/Feature/Http/Requests/UserUpdateRequestTest.php

@@ -1,13 +1,16 @@
 <?php
 
-namespace Tests\Api\v1\Requests;
+namespace Tests\Feature\Http\Requests;
 
-use App\Api\v1\Requests\UserUpdateRequest;
+use App\Http\Requests\UserUpdateRequest;
 use Illuminate\Foundation\Testing\WithoutMiddleware;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Validator;
 use Tests\TestCase;
 
+/**
+ * @covers \App\Http\Requests\UserUpdateRequest
+ */
 class UserUpdateRequestTest extends TestCase
 {
 

+ 85 - 0
tests/Feature/Http/Requests/WebauthnRenameRequestTest.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace Tests\Feature\Http\Requests;
+
+use App\Http\Requests\WebauthnRenameRequest;
+use Illuminate\Foundation\Testing\WithoutMiddleware;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Validator;
+use Tests\TestCase;
+
+/**
+ * @covers \App\Http\Requests\WebauthnRenameRequest
+ */
+class WebauthnRenameRequestTest extends TestCase
+{
+
+    use WithoutMiddleware;
+
+    /**
+     * @test
+     */
+    public function test_user_is_authorized()
+    {
+        Auth::shouldReceive('check')
+        ->once()
+        ->andReturn(true);
+
+        $request = new WebauthnRenameRequest();
+    
+        $this->assertTrue($request->authorize());
+    }
+
+    /**
+     * @dataProvider provideValidData
+     */
+    public function test_valid_data(array $data) : void
+    {
+        $request = new WebauthnRenameRequest();
+        $validator = Validator::make($data, $request->rules());
+
+        $this->assertFalse($validator->fails());
+    }
+
+    /**
+     * Provide Valid data for validation test
+     */
+    public function provideValidData() : array
+    {
+        return [
+            [[
+                'name'  => 'Yubikey',
+            ]],
+        ];
+    }
+
+    /**
+     * @dataProvider provideInvalidData
+     */
+    public function test_invalid_data(array $data) : void
+    {        
+        $request = new WebauthnRenameRequest();
+        $validator = Validator::make($data, $request->rules());
+
+        $this->assertTrue($validator->fails());
+    }
+
+    /**
+     * Provide invalid data for validation test
+     */
+    public function provideInvalidData() : array
+    {
+        return [
+            [[
+                'name'  => '', // required
+            ]],
+            [[
+                'name'  => true, // string
+            ]],
+            [[
+                'name'  => 0, // string
+            ]],
+        ];
+    }
+
+}

+ 80 - 0
tests/Feature/Middlewares/AuthenticateMiddlewareTest.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace Tests\Feature\Http\Middlewares;
+
+use App\Models\User;
+use Tests\FeatureTestCase;
+use Illuminate\Support\Facades\Config;
+
+
+class AuthenticateMiddlewareTest extends FeatureTestCase
+{
+
+    private const USER_NAME = 'John';
+    private const USER_EMAIL = 'john@example.com';
+
+    /**
+     * @test
+     */
+    public function test_it_always_authenticates_with_reverse_proxy_guard()
+    {
+        Config::set('auth.auth_proxy_headers.user', 'HTTP_REMOTE_USER');
+        
+        $this->app['auth']->shouldUse('reverse-proxy-guard');
+
+        $this->json('GET', '/api/v1/groups', [], ['HTTP_REMOTE_USER' => self::USER_NAME]);
+        $this->assertAuthenticated('reverse-proxy-guard');
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_user_is_set_from_reverse_proxy_info()
+    {
+        Config::set('auth.auth_proxy_headers.user', 'HTTP_REMOTE_USER');
+        Config::set('auth.auth_proxy_headers.email', 'HTTP_REMOTE_EMAIL');
+
+        $this->app['auth']->shouldUse('reverse-proxy-guard');
+
+        $this->json('GET', '/api/v1/groups', [], [
+            'HTTP_REMOTE_USER' => self::USER_NAME,
+            'HTTP_REMOTE_EMAIL' => self::USER_EMAIL
+        ]);
+        $this->assertAuthenticated('reverse-proxy-guard');
+
+        $user = $this->app->make('auth')->guard('reverse-proxy-guard')->user();
+        $this->assertEquals(self::USER_NAME, $user->name);
+        $this->assertEquals(self::USER_EMAIL, $user->email);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_it_does_not_authenticate_with_empty_header()
+    {
+        Config::set('auth.auth_proxy_headers.user', 'HTTP_REMOTE_USER');
+        Config::set('auth.auth_proxy_headers.email', 'HTTP_REMOTE_EMAIL');
+
+        $this->app['auth']->shouldUse('reverse-proxy-guard');
+
+        $this->json('GET', '/api/v1/groups', [], [
+            'HTTP_REMOTE_USER' => '',
+            'HTTP_REMOTE_EMAIL' => ''
+        ])->assertUnauthorized();
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_it_does_not_authenticate_with_missing_header()
+    {
+        $this->app['auth']->shouldUse('reverse-proxy-guard');
+
+        $this->json('GET', '/api/v1/groups', [], [])
+            ->assertUnauthorized();
+    }
+
+}

+ 2 - 2
tests/Feature/Services/SettingServiceTest.php

@@ -148,8 +148,6 @@ class SettingServiceTest extends FeatureTestCase
 
         $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);
 
@@ -157,6 +155,8 @@ class SettingServiceTest extends FeatureTestCase
             $this->assertArrayHasKey($key, $all);
             $this->assertEquals($all[$key], $val);
         }
+        
+        $this->assertArrayHasKey('lang', $all);
 
     }
 

+ 0 - 4
tests/Unit/Api/v1/Controllers/GroupControllerTest.php

@@ -2,7 +2,6 @@
 
 namespace Tests\Unit\Api\v1\Controllers;
 
-use App\Models\User;
 use App\Models\Group;
 use Tests\TestCase;
 use App\Models\TwoFAccount;
@@ -10,9 +9,6 @@ use App\Services\GroupService;
 use Illuminate\Foundation\Testing\WithoutMiddleware;
 use App\Api\v1\Controllers\GroupController;
 use Mockery;
-use Illuminate\Http\Request;
-use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
-use App\Api\v1\Requests\GroupStoreRequest;
 
 /**
  * @covers \App\Api\v1\Controllers\GroupController

+ 26 - 0
tests/Unit/Extensions/RemoteUserProviderTest.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Tests\Unit\Extensions;
+
+use Tests\TestCase;
+use App\Extensions\RemoteUserProvider;
+
+
+/**
+ * @covers \App\Extensions\RemoteUserProvider
+ */
+class RemoteUserProviderTest extends TestCase
+{
+    public function test_retreiving_a_user_returns_a_non_persisted_user_instance()
+    {
+        $provider = new RemoteUserProvider;
+
+        $user = $provider->retrieveById([
+            'user' => 'testUser',
+            'email' => 'test@example.org'
+        ]);
+
+        $this->assertInstanceOf('\App\Models\User', $user);
+        $this->assertEquals(false, $user->exists);
+    }
+}

+ 0 - 2
tests/Unit/Listeners/DissociateTwofaccountFromGroupTest.php

@@ -3,11 +3,9 @@
 namespace Tests\Unit\Listeners;
 
 use App\Models\Group;
-use App\Models\TwoFAccount;
 use App\Events\GroupDeleting;
 use Tests\FeatureTestCase;
 use App\Listeners\DissociateTwofaccountFromGroup;
-use Illuminate\Support\Facades\Storage;
 
 
 /**