浏览代码

Complete tests rewriting for main controllers

Bubka 3 年之前
父节点
当前提交
22442f7af6

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

@@ -126,8 +126,8 @@ class GroupControllerTest extends FeatureTestCase
 
         $response = $this->actingAs($this->user, 'api')
             ->json('PUT', '/api/v1/groups/' . $group->id, [
-                    'name' => 'name updated',
-                ])
+                'name' => 'name updated',
+            ])
             ->assertOk()
             ->assertExactJson([
                 'id' => 1,
@@ -144,8 +144,8 @@ class GroupControllerTest extends FeatureTestCase
     {
         $response = $this->actingAs($this->user, 'api')
             ->json('PUT', '/api/v1/groups/1000', [
-                    'name' => 'testUpdate',
-                ])
+                'name' => 'testUpdate',
+            ])
             ->assertNotFound()
             ->assertJsonStructure([
                 'message'
@@ -162,8 +162,8 @@ class GroupControllerTest extends FeatureTestCase
 
         $response = $this->actingAs($this->user, 'api')
             ->json('PUT', '/api/v1/groups/' . $group->id, [
-                    'name' => null,
-                ])
+                'name' => null,
+            ])
             ->assertStatus(422);
     }
 
@@ -178,8 +178,8 @@ class GroupControllerTest extends FeatureTestCase
 
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
-                    'ids' => [1,2],
-                ])
+                'ids' => [1,2],
+            ])
             ->assertOk()
             ->assertExactJson([
                 'id' => $group->id,
@@ -198,8 +198,8 @@ class GroupControllerTest extends FeatureTestCase
 
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/groups/1000/assign', [
-                    'ids' => [1,2],
-                ])
+                'ids' => [1,2],
+            ])
             ->assertNotFound()
             ->assertJsonStructure([
                 'message'
@@ -217,8 +217,8 @@ class GroupControllerTest extends FeatureTestCase
 
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
-                    'ids' => 1,
-                ])
+                'ids' => 1,
+            ])
             ->assertStatus(422);
     }
 
@@ -233,7 +233,7 @@ class GroupControllerTest extends FeatureTestCase
 
         $assign = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
-                    'ids' => [1,2],
+                'ids' => [1,2],
             ]);
 
         $response = $this->actingAs($this->user, 'api')
@@ -266,7 +266,7 @@ class GroupControllerTest extends FeatureTestCase
 
         $assign = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [
-                    'ids' => [1,2],
+                'ids' => [1,2],
             ]);
 
         $response = $this->actingAs($this->user, 'api')

+ 4 - 4
tests/Api/v1/Controllers/IconControllerTest.php

@@ -20,8 +20,8 @@ class IconControllerTest extends TestCase
         $file = UploadedFile::fake()->image('testIcon.jpg');
 
         $response = $this->json('POST', '/api/v1/icons', [
-                    'icon' => $file,
-                ])
+                'icon' => $file,
+            ])
             ->assertCreated()
             ->assertJsonStructure([
                 'filename'
@@ -35,8 +35,8 @@ class IconControllerTest extends TestCase
     public function test_upload_with_invalid_data_returns_validation_error()
     {
         $response = $this->json('POST', '/api/v1/icons', [
-                    'icon' => null,
-                ])
+                'icon' => null,
+            ])
             ->assertStatus(422);
     }
 

+ 2 - 3
tests/Api/v1/Controllers/QrcodeControllerTest.php

@@ -93,11 +93,10 @@ class QrcodeControllerTest extends FeatureTestCase
      */
     public function test_decode_missing_qrcode_return_validation_error()
     {
-
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/qrcode/decode', [
-                    'qrcode' => '',
-                ])
+                'qrcode' => '',
+            ])
             ->assertStatus(422);
     }
 

+ 261 - 0
tests/Api/v1/Controllers/SettingControllerTest.php

@@ -0,0 +1,261 @@
+<?php
+
+namespace Tests\Api\v1\Controllers;
+
+use App\User;
+use App\Group;
+use Tests\FeatureTestCase;
+use App\TwoFAccount;
+
+class SettingControllerTest extends FeatureTestCase
+{
+    /**
+     * @var \App\User
+    */
+    protected $user;
+
+    private const SETTING_JSON_STRUCTURE = [
+        'key',
+        'value'
+    ];
+    private const TWOFAUTH_NATIVE_SETTING = 'showTokenAsDot';
+    private const TWOFAUTH_NATIVE_SETTING_DEFAULT_VALUE = false;
+    private const TWOFAUTH_NATIVE_SETTING_CHANGED_VALUE = true;
+    private const USER_DEFINED_SETTING = 'mySetting';
+    private const USER_DEFINED_SETTING_VALUE = 'mySetting';
+    private const USER_DEFINED_SETTING_CHANGED_VALUE = 'mySetting';
+
+    /**
+     * @test
+     */
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->user = factory(User::class)->create();
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_index_returns_setting_collection()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('GET', '/api/v1/settings')
+            ->assertOk()
+            ->assertJsonStructure([
+                '*' => self::SETTING_JSON_STRUCTURE
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_show_native_unchanged_setting_returns_consistent_value()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('GET', '/api/v1/settings/' . self::TWOFAUTH_NATIVE_SETTING)
+            ->assertOk()
+            ->assertExactJson([
+                'key' => self::TWOFAUTH_NATIVE_SETTING,
+                'value' => self::TWOFAUTH_NATIVE_SETTING_DEFAULT_VALUE,
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_show_native_changed_setting_returns_consistent_value()
+    {
+        $settingService = resolve('App\Services\SettingServiceInterface');
+        $settingService->set(self::TWOFAUTH_NATIVE_SETTING, self::TWOFAUTH_NATIVE_SETTING_CHANGED_VALUE);
+
+        $response = $this->actingAs($this->user, 'api')
+            ->json('GET', '/api/v1/settings/' . self::TWOFAUTH_NATIVE_SETTING)
+            ->assertOk()
+            ->assertExactJson([
+                'key' => self::TWOFAUTH_NATIVE_SETTING,
+                'value' => self::TWOFAUTH_NATIVE_SETTING_CHANGED_VALUE,
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_show_custom_user_setting_returns_consistent_value()
+    {
+        $settingService = resolve('App\Services\SettingServiceInterface');
+        $settingService->set(self::USER_DEFINED_SETTING, self::USER_DEFINED_SETTING_VALUE);
+
+        $response = $this->actingAs($this->user, 'api')
+            ->json('GET', '/api/v1/settings/' . self::USER_DEFINED_SETTING)
+            ->assertOk()
+            ->assertExactJson([
+                'key' => self::USER_DEFINED_SETTING,
+                'value' => self::USER_DEFINED_SETTING_VALUE,
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_show_missing_setting_returns_not_found()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('GET', '/api/v1/settings/missing')
+            ->assertNotFound();
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_store_custom_user_setting_returns_success()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('POST', '/api/v1/settings', [
+                'key' => self::USER_DEFINED_SETTING,
+                'value' => self::USER_DEFINED_SETTING_VALUE,
+            ])
+            ->assertCreated()
+            ->assertExactJson([
+                'key' => self::USER_DEFINED_SETTING,
+                'value' => self::USER_DEFINED_SETTING_VALUE,
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_store_invalid_custom_user_setting_returns_validation_error()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('POST', '/api/v1/settings', [
+                'key' => null,
+                'value' => null,
+            ])
+            ->assertStatus(422);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_store_existing_custom_user_setting_returns_validation_error()
+    {
+        $settingService = resolve('App\Services\SettingServiceInterface');
+        $settingService->set(self::USER_DEFINED_SETTING, self::USER_DEFINED_SETTING_VALUE);
+
+        $response = $this->actingAs($this->user, 'api')
+            ->json('POST', '/api/v1/settings', [
+                'key' => self::USER_DEFINED_SETTING,
+                'value' => self::USER_DEFINED_SETTING_VALUE,
+            ])
+            ->assertStatus(422);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_update_unchanged_native_setting_returns_updated_setting()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('PUT', '/api/v1/settings/' . self::TWOFAUTH_NATIVE_SETTING, [
+                'key' => self::TWOFAUTH_NATIVE_SETTING,
+                'value' => self::TWOFAUTH_NATIVE_SETTING_CHANGED_VALUE,
+            ])
+            ->assertOk()
+            ->assertExactJson([
+                'key' => self::TWOFAUTH_NATIVE_SETTING,
+                'value' => self::TWOFAUTH_NATIVE_SETTING_CHANGED_VALUE,
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_update_custom_user_setting_returns_updated_setting()
+    {
+        $settingService = resolve('App\Services\SettingServiceInterface');
+        $settingService->set(self::USER_DEFINED_SETTING, self::USER_DEFINED_SETTING_VALUE);
+
+        $response = $this->actingAs($this->user, 'api')
+            ->json('PUT', '/api/v1/settings/' . self::USER_DEFINED_SETTING, [
+                'key' => self::USER_DEFINED_SETTING,
+                'value' => self::USER_DEFINED_SETTING_CHANGED_VALUE,
+            ])
+            ->assertOk()
+            ->assertExactJson([
+                'key' => self::USER_DEFINED_SETTING,
+                'value' => self::USER_DEFINED_SETTING_CHANGED_VALUE,
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_update_missing_user_setting_returns_created_setting()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('PUT', '/api/v1/settings/' . self::USER_DEFINED_SETTING, [
+                'key' => self::USER_DEFINED_SETTING,
+                'value' => self::USER_DEFINED_SETTING_CHANGED_VALUE,
+            ])
+            ->assertOk()
+            ->assertExactJson([
+                'key' => self::USER_DEFINED_SETTING,
+                'value' => self::USER_DEFINED_SETTING_CHANGED_VALUE,
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_destroy_user_setting_returns_success()
+    {
+        $settingService = resolve('App\Services\SettingServiceInterface');
+        $settingService->set(self::USER_DEFINED_SETTING, self::USER_DEFINED_SETTING_VALUE);
+
+        $response = $this->actingAs($this->user, 'api')
+            ->json('DELETE', '/api/v1/settings/' . self::USER_DEFINED_SETTING)
+            ->assertNoContent();
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_destroy_native_setting_returns_bad_request()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('DELETE', '/api/v1/settings/' . self::TWOFAUTH_NATIVE_SETTING)
+            ->assertStatus(400)
+            ->assertJsonStructure([
+                'message',
+                'reason',
+            ]);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_destroy_missing_user_setting_returns_not_found()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('DELETE', '/api/v1/settings/' . self::USER_DEFINED_SETTING)
+            ->assertNotFound();
+    }
+
+
+}

+ 406 - 533
tests/Api/v1/Controllers/TwoFAccountControllerTest.php

@@ -26,13 +26,127 @@ class TwoFAccountControllerTest extends FeatureTestCase
     private const PERIOD_CUSTOM = 40;
     private const COUNTER_DEFAULT = 0;
     private const COUNTER_CUSTOM = 5;
+    private const IMAGE = 'https%3A%2F%2Fen.opensuse.org%2Fimages%2F4%2F44%2FButton-filled-colour.png';
     private const ICON = 'test.png';
-    private const TOTP_FULL_CUSTOM_URI = 'otpauth://totp/'.self::SERVICE.':'.self::ACCOUNT.'?secret='.self::SECRET.'&issuer='.self::SERVICE.'&digits='.self::DIGITS_CUSTOM.'&period='.self::PERIOD_CUSTOM.'&algorithm='.self::ALGORITHM_CUSTOM;
-    private const HOTP_FULL_CUSTOM_URI = 'otpauth://hotp/'.self::SERVICE.':'.self::ACCOUNT.'?secret='.self::SECRET.'&issuer='.self::SERVICE.'&digits='.self::DIGITS_CUSTOM.'&counter='.self::COUNTER_CUSTOM.'&algorithm='.self::ALGORITHM_CUSTOM;
+    private const TOTP_FULL_CUSTOM_URI = 'otpauth://totp/'.self::SERVICE.':'.self::ACCOUNT.'?secret='.self::SECRET.'&issuer='.self::SERVICE.'&digits='.self::DIGITS_CUSTOM.'&period='.self::PERIOD_CUSTOM.'&algorithm='.self::ALGORITHM_CUSTOM.'&image='.self::IMAGE;
+    private const HOTP_FULL_CUSTOM_URI = 'otpauth://hotp/'.self::SERVICE.':'.self::ACCOUNT.'?secret='.self::SECRET.'&issuer='.self::SERVICE.'&digits='.self::DIGITS_CUSTOM.'&counter='.self::COUNTER_CUSTOM.'&algorithm='.self::ALGORITHM_CUSTOM.'&image='.self::IMAGE;
     private const TOTP_SHORT_URI = 'otpauth://totp/'.self::ACCOUNT.'?secret='.self::SECRET;
     private const HOTP_SHORT_URI = 'otpauth://hotp/'.self::ACCOUNT.'?secret='.self::SECRET;
+    private const TOTP_URI_WITH_UNREACHABLE_IMAGE = 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&image=https%3A%2F%2Fen.opensuse.org%2Fimage.png';
     private const INVALID_OTPAUTH_URI = 'otpauth://Xotp/'.self::ACCOUNT.'?secret='.self::SECRET;
-
+    private const VALID_RESOURCE_STRUCTURE_WITHOUT_SECRET = [
+        'id',
+        'group_id',
+        'service',
+        'account',
+        'icon',
+        'otp_type',
+        'digits',
+        'algorithm',
+        'period',
+        'counter'
+    ];
+    private const VALID_RESOURCE_STRUCTURE_WITH_SECRET = [
+        'id',
+        'group_id',
+        'service',
+        'account',
+        'icon',
+        'otp_type',
+        'secret',
+        'digits',
+        'algorithm',
+        'period',
+        'counter'
+    ];
+    private const VALID_OTP_RESOURCE_STRUCTURE_FOR_TOTP = [
+        'generated_at',
+        'otp_type',
+        'password',
+        'period',
+    ];
+    private const VALID_OTP_RESOURCE_STRUCTURE_FOR_HOTP = [
+        'otp_type',
+        'password',
+        'counter',
+    ];
+    private const ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP = [
+        'service'   => self::SERVICE,
+        'account'   => self::ACCOUNT,
+        'icon'      => self::ICON,
+        'otp_type'  => 'totp',
+        'secret'    => self::SECRET,
+        'digits'    => self::DIGITS_CUSTOM,
+        'algorithm' => self::ALGORITHM_CUSTOM,
+        'period'    => self::PERIOD_CUSTOM,
+        'counter'   => null,
+    ];
+    private const ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP = [
+        'account'   => self::ACCOUNT,
+        'otp_type'  => 'totp',
+        'secret'    => self::SECRET,
+    ];
+    private const JSON_FRAGMENTS_FOR_CUSTOM_TOTP = [
+        'service'   => self::SERVICE,
+        'account'   => self::ACCOUNT,
+        'otp_type'  => 'totp',
+        'secret'    => self::SECRET,
+        'digits'    => self::DIGITS_CUSTOM,
+        'algorithm' => self::ALGORITHM_CUSTOM,
+        'period'    => self::PERIOD_CUSTOM,
+        'counter'   => null,
+    ];
+    private const JSON_FRAGMENTS_FOR_DEFAULT_TOTP = [
+        'service'   => null,
+        'account'   => self::ACCOUNT,
+        'otp_type'  => 'totp',
+        'secret'    => self::SECRET,
+        'digits'    => self::DIGITS_DEFAULT,
+        'algorithm' => self::ALGORITHM_DEFAULT,
+        'period'    => self::PERIOD_DEFAULT,
+        'counter'   => null,
+    ];
+    private const ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP = [
+        'service'   => self::SERVICE,
+        'account'   => self::ACCOUNT,
+        'icon'      => self::ICON,
+        'otp_type'  => 'hotp',
+        'secret'    => self::SECRET,
+        'digits'    => self::DIGITS_CUSTOM,
+        'algorithm' => self::ALGORITHM_CUSTOM,
+        'period'    => null,
+        'counter'   => self::COUNTER_CUSTOM,
+    ];
+    private const ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_HOTP = [
+        'account'   => self::ACCOUNT,
+        'otp_type'  => 'hotp',
+        'secret'    => self::SECRET,
+    ];
+    private const JSON_FRAGMENTS_FOR_CUSTOM_HOTP = [
+        'service'   => self::SERVICE,
+        'account'   => self::ACCOUNT,
+        'otp_type'  => 'hotp',
+        'secret'    => self::SECRET,
+        'digits'    => self::DIGITS_CUSTOM,
+        'algorithm' => self::ALGORITHM_CUSTOM,
+        'period'    => null,
+        'counter'   => self::COUNTER_CUSTOM,
+    ];
+    private const JSON_FRAGMENTS_FOR_DEFAULT_HOTP = [
+        'service' => null,
+        'account'   => self::ACCOUNT,
+        'otp_type'  => 'hotp',
+        'secret'    => self::SECRET,
+        'digits'    => self::DIGITS_DEFAULT,
+        'algorithm' => self::ALGORITHM_DEFAULT,
+        'period'    => null,
+        'counter'   => self::COUNTER_DEFAULT,
+    ];
+    private const ARRAY_OF_INVALID_PARAMETERS = [
+        'account'   => null,
+        'otp_type'  => 'totp',
+        'secret'    => self::SECRET,
+    ];
 
     /**
      * @test
@@ -50,27 +164,15 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_index_returns_twofaccount_collection()
     {
-        $twofaccount = factory(TwoFAccount::class, 3)->create();
+        factory(TwoFAccount::class, 3)->create();
 
         $response = $this->actingAs($this->user, 'api')
             ->json('GET', '/api/v1/twofaccounts')
             ->assertOk()
             ->assertJsonCount(3, $key = null)
             ->assertJsonStructure([
-                '*' => [
-                    'id',
-                    'group_id',
-                    'service',
-                    'account',
-                    'icon',
-                    'otp_type',
-                    'digits',
-                    'algorithm',
-                    'period',
-                    'counter'
-                ]
-            ]
-        );
+                '*' => self::VALID_RESOURCE_STRUCTURE_WITHOUT_SECRET
+            ]);
     }
 
 
@@ -79,54 +181,29 @@ class TwoFAccountControllerTest extends FeatureTestCase
      */
     public function test_index_returns_twofaccount_collection_with_secret()
     {
-        $twofaccount = factory(TwoFAccount::class, 3)->create();
+        factory(TwoFAccount::class, 3)->create();
 
         $response = $this->actingAs($this->user, 'api')
             ->json('GET', '/api/v1/twofaccounts?withSecret=1')
             ->assertOk()
             ->assertJsonCount(3, $key = null)
             ->assertJsonStructure([
-                '*' => [
-                    'id',
-                    'group_id',
-                    'service',
-                    'account',
-                    'icon',
-                    'otp_type',
-                    'secret',
-                    'digits',
-                    'algorithm',
-                    'period',
-                    'counter'
-                ]
-            ]
-        );
+                '*' => self::VALID_RESOURCE_STRUCTURE_WITH_SECRET
+            ]);
     }
 
 
     /**
      * @test
      */
-    public function test_show_twofaccount_returns_twofaccount_resource()
+    public function test_show_twofaccount_returns_twofaccount_resource_with_secret()
     {
         $twofaccount = factory(TwoFAccount::class)->create();
 
         $response = $this->actingAs($this->user, 'api')
             ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id)
             ->assertOk()
-            ->assertJsonStructure([
-                'id',
-                'group_id',
-                'service',
-                'account',
-                'icon',
-                'otp_type',
-                'secret',
-                'digits',
-                'algorithm',
-                'period',
-                'counter'
-            ]);
+            ->assertJsonStructure(self::VALID_RESOURCE_STRUCTURE_WITH_SECRET);
     }
 
 
@@ -140,17 +217,32 @@ class TwoFAccountControllerTest extends FeatureTestCase
         $response = $this->actingAs($this->user, 'api')
             ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '?withSecret=0')
             ->assertOk()
-            ->assertJsonStructure([
-                'id',
-                'group_id',
-                'service',
-                'account',
-                'icon',
-                'otp_type',
-                'digits',
-                'algorithm',
-                'period',
-                'counter'
+            ->assertJsonStructure(self::VALID_RESOURCE_STRUCTURE_WITHOUT_SECRET);
+    }
+
+
+    /**
+     * @test
+     */
+    public function test_show_twofaccount_with_indeciphered_data_returns_replaced_data()
+    {
+        $dbEncryptionService = resolve('App\Services\DbEncryptionService');
+        $dbEncryptionService->setTo(true);
+
+        $twofaccount = factory(TwoFAccount::class)->create();
+
+        DB::table('twofaccounts')
+            ->where('id', $twofaccount->id)
+            ->update([
+                'secret' => '**encrypted**',
+                'account' => '**encrypted**',
+            ]);
+
+        $response = $this->actingAs($this->user, 'api')
+            ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id)
+            ->assertJsonFragment([
+                'secret' => '*indecipherable*',
+                'account' => '*indecipherable*',
             ]);
     }
 
@@ -180,19 +272,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/twofaccounts', $data)
             ->assertCreated()
-            ->assertJsonStructure([
-                'id',
-                'group_id',
-                'service',
-                'account',
-                'icon',
-                'otp_type',
-                'secret',
-                'digits',
-                'algorithm',
-                'period',
-                'counter'
-            ]);
+            ->assertJsonStructure(self::VALID_RESOURCE_STRUCTURE_WITH_SECRET);
     }
 
 
@@ -208,44 +288,24 @@ class TwoFAccountControllerTest extends FeatureTestCase
             [[
                 'uri' => self::TOTP_SHORT_URI,
             ]],
-            [[
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'icon'      => self::ICON,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => self::PERIOD_CUSTOM,
-                'counter'   => null,
-            ]],
-            [[
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-            ]],
+            [
+                self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP
+            ],
+            [
+                self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP
+            ],
             [[
                 'uri' => self::HOTP_FULL_CUSTOM_URI,
             ]],
             [[
                 'uri' => self::HOTP_SHORT_URI,
             ]],
-            [[
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'icon'      => self::ICON,
-                'otp_type'  => 'hotp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => null,
-                'counter'   => self::COUNTER_CUSTOM,
-            ]],
-            [[
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'hotp',
-                'secret'    => self::SECRET,
-            ]],
+            [
+                self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP
+            ],
+            [
+                self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_HOTP
+            ],
         ];
     }
 
@@ -257,18 +317,9 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/twofaccounts', [
-                    'uri' => self::TOTP_FULL_CUSTOM_URI,
-                ])
-            ->assertJsonFragment([
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => self::PERIOD_CUSTOM,
-                'counter'   => null,
-            ]);
+                'uri' => self::TOTP_FULL_CUSTOM_URI,
+            ])
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP);
     }
 
 
@@ -279,18 +330,9 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/twofaccounts', [
-                    'uri' => self::TOTP_SHORT_URI,
-                ])
-            ->assertJsonFragment([
-                'service'   => null,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_DEFAULT,
-                'algorithm' => self::ALGORITHM_DEFAULT,
-                'period'    => self::PERIOD_DEFAULT,
-                'counter'   => null,
-            ]);
+                'uri' => self::TOTP_SHORT_URI,
+            ])
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP);
     }
 
 
@@ -300,26 +342,8 @@ class TwoFAccountControllerTest extends FeatureTestCase
     public function test_store_totp_using_fully_custom_parameters_returns_consistent_resource()
     {
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts', [
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => self::PERIOD_CUSTOM,
-                'counter'   => null,
-            ])
-            ->assertJsonFragment([
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => self::PERIOD_CUSTOM,
-                'counter'   => null,
-            ]);
+            ->json('POST', '/api/v1/twofaccounts', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP)
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP);
     }
 
 
@@ -329,21 +353,8 @@ class TwoFAccountControllerTest extends FeatureTestCase
     public function test_store_totp_using_minimum_parameters_returns_consistent_resource()
     {
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts', [
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-            ])
-            ->assertJsonFragment([
-                'service'   => null,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_DEFAULT,
-                'algorithm' => self::ALGORITHM_DEFAULT,
-                'period'    => self::PERIOD_DEFAULT,
-                'counter'   => null,
-            ]);
+            ->json('POST', '/api/v1/twofaccounts', self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP)
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP);
     }
 
 
@@ -354,18 +365,9 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/twofaccounts', [
-                    'uri' => self::HOTP_FULL_CUSTOM_URI,
-                ])
-            ->assertJsonFragment([
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'hotp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => null,
-                'counter'   => self::COUNTER_CUSTOM,
-            ]);
+                'uri' => self::HOTP_FULL_CUSTOM_URI,
+            ])
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP);
     }
 
 
@@ -376,18 +378,9 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/twofaccounts', [
-                    'uri' => self::HOTP_SHORT_URI,
-                ])
-            ->assertJsonFragment([
-                'service' => null,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'hotp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_DEFAULT,
-                'algorithm' => self::ALGORITHM_DEFAULT,
-                'period'    => null,
-                'counter'   => self::COUNTER_DEFAULT,
-            ]);
+                'uri' => self::HOTP_SHORT_URI,
+            ])
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_DEFAULT_HOTP);
     }
 
 
@@ -397,26 +390,8 @@ class TwoFAccountControllerTest extends FeatureTestCase
     public function test_store_hotp_using_fully_custom_parameters_returns_consistent_resource()
     {
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts', [
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'hotp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => null,
-                'counter'   => self::COUNTER_CUSTOM,
-            ])
-            ->assertJsonFragment([
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'hotp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => null,
-                'counter'   => self::COUNTER_CUSTOM,
-            ]);
+            ->json('POST', '/api/v1/twofaccounts', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP)
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP);
     }
 
 
@@ -426,21 +401,8 @@ class TwoFAccountControllerTest extends FeatureTestCase
     public function test_store_hotp_using_minimum_parameters_returns_consistent_resource()
     {
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts', [
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'hotp',
-                'secret'    => self::SECRET,
-            ])
-            ->assertJsonFragment([
-                'service'   => null,
-                'account'   => self::ACCOUNT,
-                'otp_type'  => 'hotp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_DEFAULT,
-                'algorithm' => self::ALGORITHM_DEFAULT,
-                'period'    => null,
-                'counter'   => self::COUNTER_DEFAULT,
-            ]);
+            ->json('POST', '/api/v1/twofaccounts', self::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_HOTP)
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_DEFAULT_HOTP);
     }
 
 
@@ -451,8 +413,8 @@ class TwoFAccountControllerTest extends FeatureTestCase
     {
         $response = $this->actingAs($this->user, 'api')
             ->json('POST', '/api/v1/twofaccounts', [
-                    'uri' => self::INVALID_OTPAUTH_URI,
-                ])
+                'uri' => self::INVALID_OTPAUTH_URI,
+            ])
             ->assertStatus(422);
     }
 
@@ -465,29 +427,9 @@ class TwoFAccountControllerTest extends FeatureTestCase
         $twofaccount = factory(TwoFAccount::class)->create();
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('PUT', '/api/v1/twofaccounts/' . $twofaccount->id, [
-                    'service'   => self::SERVICE,
-                    'account'   => self::ACCOUNT,
-                    'icon'      => self::ICON,
-                    'otp_type'  => 'totp',
-                    'secret'    => self::SECRET,
-                    'digits'    => self::DIGITS_CUSTOM,
-                    'algorithm' => self::ALGORITHM_CUSTOM,
-                    'period'    => self::PERIOD_CUSTOM,
-                    'counter'   => null,
-                ])
+            ->json('PUT', '/api/v1/twofaccounts/' . $twofaccount->id, self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP)
             ->assertOk()
-            ->assertJsonFragment([
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'icon'      => self::ICON,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => self::PERIOD_CUSTOM,
-                'counter'   => null,
-            ]);
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP);
     }
 
 
@@ -499,29 +441,9 @@ class TwoFAccountControllerTest extends FeatureTestCase
         $twofaccount = factory(TwoFAccount::class)->create();
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('PUT', '/api/v1/twofaccounts/' . $twofaccount->id, [
-                    'service'   => self::SERVICE,
-                    'account'   => self::ACCOUNT,
-                    'icon'      => self::ICON,
-                    'otp_type'  => 'hotp',
-                    'secret'    => self::SECRET,
-                    'digits'    => self::DIGITS_CUSTOM,
-                    'algorithm' => self::ALGORITHM_CUSTOM,
-                    'period'    => null,
-                    'counter'   => self::COUNTER_CUSTOM,
-                ])
+            ->json('PUT', '/api/v1/twofaccounts/' . $twofaccount->id, self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP)
             ->assertOk()
-            ->assertJsonFragment([
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'icon'      => self::ICON,
-                'otp_type'  => 'hotp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => null,
-                'counter'   => self::COUNTER_CUSTOM,
-            ]);
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP);
     }
 
 
@@ -531,17 +453,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
     public function test_update_missing_twofaccount_returns_not_found()
     {
         $response = $this->actingAs($this->user, 'api')
-            ->json('PUT', '/api/v1/twofaccounts/1000', [
-                'service'   => self::SERVICE,
-                'account'   => self::ACCOUNT,
-                'icon'      => self::ICON,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => self::PERIOD_CUSTOM,
-                'counter'   => null,
-            ])
+            ->json('PUT', '/api/v1/twofaccounts/1000', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP)
             ->assertNotFound();
     }
 
@@ -554,432 +466,393 @@ class TwoFAccountControllerTest extends FeatureTestCase
         $twofaccount = factory(TwoFAccount::class)->create();
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('PUT', '/api/v1/twofaccounts/' . $twofaccount->id, [
-                'service'   => self::SERVICE,
-                'account'   => null,
-                'icon'      => self::ICON,
-                'otp_type'  => 'totp',
-                'secret'    => self::SECRET,
-                'digits'    => self::DIGITS_CUSTOM,
-                'algorithm' => self::ALGORITHM_CUSTOM,
-                'period'    => self::PERIOD_CUSTOM,
-                'counter'   => null,
-            ])
+            ->json('PUT', '/api/v1/twofaccounts/' . $twofaccount->id, self::ARRAY_OF_INVALID_PARAMETERS)
             ->assertStatus(422);
     }
 
 
+    /**
+     * @test
+     */
+    public function test_reorder_returns_success()
+    {
+        factory(TwoFAccount::class, 3)->create();
 
+        $response = $this->actingAs($this->user, 'api')
+            ->json('POST', '/api/v1/twofaccounts/reorder', [
+                'orderedIds' => [3,2,1]])
+            ->assertStatus(200)
+            ->assertJsonStructure([
+                'message'
+            ]);
+    }
 
 
+    /**
+     * @test
+     */
+    public function test_reorder_with_invalid_data_returns_validation_error()
+    {
+        factory(TwoFAccount::class, 3)->create();
 
+        $response = $this->actingAs($this->user, 'api')
+            ->json('POST', '/api/v1/twofaccounts/reorder', [
+                'orderedIds' => '3,2,1'])
+            ->assertStatus(422);
+    }
 
 
+    /**
+     * @test
+     */
+    public function test_preview_returns_success_with_resource()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('POST', '/api/v1/twofaccounts/preview', [
+                'uri' => self::TOTP_FULL_CUSTOM_URI,
+            ])
+            ->assertOk()
+            ->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP);
+    }
 
 
+    /**
+     * @test
+     */
+    public function test_preview_with_invalid_data_returns_validation_error()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('POST', '/api/v1/twofaccounts/preview', [
+                'uri' => self::INVALID_OTPAUTH_URI,
+            ])
+            ->assertStatus(422);
+    }
 
 
-
-
-
-
-
-
-
-
-    
+    /**
+     * @test
+     */
+    public function test_preview_with_unreachable_image_returns_success()
+    {
+        $response = $this->actingAs($this->user, 'api')
+            ->json('POST', '/api/v1/twofaccounts/preview', [
+                'uri' => self::TOTP_URI_WITH_UNREACHABLE_IMAGE,
+            ])
+            ->assertOk()
+            ->assertJsonFragment([
+                'icon' => null
+            ]);
+    }
 
 
     /**
-     * test Hotp TwoFAccount display via API
-     *
      * @test
      */
-    public function testHotpTwofaccountDisplayWithCounterIncrement()
+    public function test_get_otp_using_totp_twofaccount_id_returns_consistent_resource()
     {
         $twofaccount = factory(TwoFAccount::class)->create([
-            'service' => 'testTOTP',
-            'account' => 'test@test.com',
-            'uri' => 'otpauth://hotp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test&counter=1',
+            'otp_type' => 'totp',
+            'account' => self::ACCOUNT,
+            'service' => self::SERVICE,
+            'secret' => self::SECRET,
+            'algorithm' => self::ALGORITHM_DEFAULT,
+            'digits' => self::DIGITS_DEFAULT,
+            'period' => self::PERIOD_DEFAULT,
+            'legacy_uri' => self::TOTP_SHORT_URI,
+            'icon' => '',
         ]);
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/otp', ['id' => $twofaccount->id])
-            ->assertStatus(200);
+            ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '/otp')
+            ->assertOk()
+            ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_TOTP)
+            ->assertJsonFragment([
+                'otp_type' => 'totp',
+                'period' => self::PERIOD_DEFAULT,
+            ]);
+    }
 
+
+    /**
+     * @test
+     */
+    public function test_get_otp_by_posting_totp_uri_returns_consistent_resource()
+    {
         $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id)
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'service' => 'testTOTP',
-                'account' => 'test@test.com',
-                'group_id' => null,
-                'isConsistent' => true,
-                'otpType' => 'hotp',
-                'digits' => 6,
-                'hotpCounter' => 2,
-                'imageLink' => null,
+            ->json('POST', '/api/v1/twofaccounts/otp', [
+                'uri' => self::TOTP_FULL_CUSTOM_URI,
             ])
-            ->assertJsonMissing([
-                'uri' => 'otpauth://hotp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'algorithm' => 'sha1',
+            ->assertOk()
+            ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_TOTP)
+            ->assertJsonFragment([
+                'otp_type' => 'totp',
+                'period' => self::PERIOD_CUSTOM,
             ]);
     }
 
 
     /**
-     * test TwoFAccount preview via API
-     *
      * @test
      */
-    public function testTwofaccountPreview()
+    public function test_get_otp_by_posting_totp_parameters_returns_consistent_resource()
     {
-        Storage::put('test.png', 'emptied to prevent missing resource replaced by null by the model getter');
-
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/preview', [
-                'uri' => 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&issuer=service&image=https%3A%2F%2Fen.opensuse.org%2Fimages%2F4%2F44%2FButton-filled-colour.png',
-            ])
-            ->assertStatus(200)
+            ->json('POST', '/api/v1/twofaccounts/otp', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP)
+            ->assertOk()
+            ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_TOTP)
             ->assertJsonFragment([
-                'service' => 'service',
-                'account' => 'account',
-                'uri' => 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&issuer=service&image=https%3A%2F%2Fen.opensuse.org%2Fimages%2F4%2F44%2FButton-filled-colour.png',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'algorithm' => 'sha1',
-                'otpType' => 'totp',
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'hotpCounter' => null,
-                'imageLink' => 'https://en.opensuse.org/images/4/44/Button-filled-colour.png',
-            ])
-            ->assertJsonStructure([
-                'icon'
+                'otp_type' => 'totp',
+                'period' => self::PERIOD_CUSTOM,
             ]);
     }
 
 
     /**
-     * test TwoFAccount preview with unreachable image parameter via API
-     *
      * @test
      */
-    public function testTwofaccountPreviewWithUnreachableImage()
+    public function test_get_otp_using_hotp_twofaccount_id_returns_consistent_resource()
     {
+        $twofaccount = factory(TwoFAccount::class)->create([
+            'otp_type' => 'hotp',
+            'account' => self::ACCOUNT,
+            'service' => self::SERVICE,
+            'secret' => self::SECRET,
+            'algorithm' => self::ALGORITHM_DEFAULT,
+            'digits' => self::DIGITS_DEFAULT,
+            'period' => null,
+            'legacy_uri' => self::HOTP_SHORT_URI,
+            'icon' => '',
+        ]);
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/preview', [
-                'uri' => 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&issuer=service&image=https%3A%2F%2Fen.opensuse.org%2Fimage.png',
-            ])
-            ->assertStatus(200)
-            ->assertJsonMissing([
-                'icon'
+            ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '/otp')
+            ->assertOk()
+            ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_HOTP)
+            ->assertJsonFragment([
+                'otp_type' => 'hotp',
+                'counter' => self::COUNTER_DEFAULT + 1,
             ]);
     }
 
 
     /**
-     * test show account when uri field remains encrypted via API
-     *
      * @test
      */
-    public function testShowAccountWithUndecipheredUri()
+    public function test_get_otp_by_posting_hotp_uri_returns_consistent_resource()
     {
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts', [
-                    'service' => 'testCreation',
-                    'account' => 'test@example.org',
-                    'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
-                    'icon' => 'test.png',
-                ])
-            ->assertStatus(201);
-
-        DB::table('twofaccounts')
-            ->where('id', 1)
-            ->update([
-                'uri' => '**encrypted**',
+            ->json('POST', '/api/v1/twofaccounts/otp', [
+                'uri' => self::HOTP_FULL_CUSTOM_URI,
+            ])
+            ->assertOk()
+            ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_HOTP)
+            ->assertJsonFragment([
+                'otp_type' => 'hotp',
+                'counter' => self::COUNTER_CUSTOM + 1,
             ]);
+    }
+
 
+    /**
+     * @test
+     */
+    public function test_get_otp_by_posting_hotp_parameters_returns_consistent_resource()
+    {
         $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/v1/twofaccounts/1')
-            ->assertStatus(200)
+            ->json('POST', '/api/v1/twofaccounts/otp', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP)
+            ->assertOk()
+            ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_HOTP)
             ->assertJsonFragment([
-                'isConsistent' => false,
+                'otp_type' => 'hotp',
+                'counter' => self::COUNTER_CUSTOM + 1,
             ]);
     }
 
 
     /**
-     * test totp  token generation for a given existing account via API
-     *
      * @test
      */
-    public function testTotpTokenGenerationWithAccountId()
+    public function test_get_otp_by_posting_multiple_inputs_returns_bad_request()
     {
-        $twofaccount = factory(TwoFAccount::class)->create([
-            'service' => 'testService',
-            'account' => 'testAccount',
-            'uri' => 'otpauth://totp/testService:testAccount?secret=A4GRFHVVRBGY7UIW&issuer=testService'
-        ]);
-
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/otp', ['id' => $twofaccount->id])
-            ->assertStatus(200)
+            ->json('POST', '/api/v1/twofaccounts/otp', [
+                'uri' => self::HOTP_FULL_CUSTOM_URI,
+                'key' => 'value',
+            ])
+            ->assertStatus(400)
             ->assertJsonStructure([
-                'token',
-                'totpTimestamp',
-                'totpPeriod',
+                'message',
+                'reason',
             ]);
     }
 
 
     /**
-     * test hotp token generation for a given existing account via API
-     *
      * @test
      */
-    public function testHotpTokenGenerationWithAccountId()
+    public function test_get_otp_using_indecipherable_twofaccount_id_returns_bad_request()
     {
-        $twofaccount = factory(TwoFAccount::class)->create([
-            'service' => 'testService',
-            'account' => 'testAccount',
-            'uri' => 'otpauth://hotp/testService:testAccount?secret=A4GRFHVVRBGY7UIW&issuer=testService&counter=1'
-        ]);
+        $dbEncryptionService = resolve('App\Services\DbEncryptionService');
+        $dbEncryptionService->setTo(true);
+
+        $twofaccount = factory(TwoFAccount::class)->create();
+
+        DB::table('twofaccounts')
+            ->where('id', $twofaccount->id)
+            ->update([
+                'secret' => '**encrypted**',
+            ]);
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/otp', ['id' => $twofaccount->id])
-            ->assertStatus(200)
+            ->json('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '/otp')
+            ->assertStatus(400)
             ->assertJsonStructure([
-                'token',
+                'message',
             ]);
     }
 
 
     /**
-     * test token generation by providing an URI via API
-     *
      * @test
      */
-    public function testTokenGenerationWithUri()
+    public function test_get_otp_using_missing_twofaccount_id_returns_not_found()
     {
-        $uri = 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&issuer=service';
-
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/otp', ['otp' => ['uri' => $uri]])
-            ->assertStatus(200)
-            ->assertJsonStructure([
-                'token',
-                'totpTimestamp',
-                'totpPeriod',
-            ]);
+            ->json('GET', '/api/v1/twofaccounts/1000/otp')
+            ->assertNotFound();
     }
 
 
     /**
-     * test totp token generation by providing an array of otp attributes without URI via API
-     *
      * @test
      */
-    public function testTotpTokenGenerationWithAttributesArray()
+    public function test_get_otp_by_posting_invalid_uri_returns_validation_error()
     {
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/otp', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'totp',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(200)
-            ->assertJsonStructure([
-                'token',
-                'totpTimestamp',
-                'totpPeriod',
-            ]);
+            ->json('POST', '/api/v1/twofaccounts/otp', [
+                'uri' => self::INVALID_OTPAUTH_URI,
+            ])
+            ->assertStatus(422);
     }
 
 
     /**
-     * test hotp token generation by providing an array of otp attributes without URI via API
-     *
      * @test
      */
-    public function testHotpTokenGenerationWithAttributesArray()
+    public function test_get_otp_by_posting_invalid_parameters_returns_validation_error()
     {
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/otp', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'hotp',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 6,
-                'hotpCounter' => 1,
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(200)
-            ->assertJsonStructure([
-                'token',
-                'hotpCounter',
-            ]);
+            ->json('POST', '/api/v1/twofaccounts/otp', self::ARRAY_OF_INVALID_PARAMETERS)
+            ->assertStatus(422);
     }
 
 
     /**
-     * test token generation by providing an array of otp attributes with a bad otp type via API
-     *
      * @test
      */
-    public function testTokenGenerationWithBadOtptypeAttribute()
+    public function test_count_returns_right_number_of_twofaccount()
     {
+        factory(TwoFAccount::class, 3)->create();
+
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/otp', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'otp',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(422)
-            ->assertJsonStructure([
-                'errors' => [
-                    'otpType'
-                ]
+            ->json('GET', '/api/v1/twofaccounts/count')
+            ->assertStatus(200)
+            ->assertExactJson([
+                'count' => 3
             ]);
     }
 
 
     /**
-     * test token generation by providing an array of otp attributes without secret via API
-     *
      * @test
      */
-    public function testTokenGenerationWithMissingSecretAttribute()
+    public function test_withdraw_returns_success()
     {
+        factory(TwoFAccount::class, 3)->create();
+        $ids = DB::table('twofaccounts')->pluck('id')->implode(',');
+
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/otp', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'totp',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 'x',
-                'totpPeriod' => 'y',
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(422)
+            ->json('PATCH', '/api/v1/twofaccounts/withdraw?ids=1,2,3' . $ids)
+            ->assertOk()
             ->assertJsonStructure([
-                'errors' => [
-                    'qrcode'
-                ]
+                'message',
             ]);
     }
 
 
     /**
-     * test token generation by providing an array of bad attributes  via API
-     *
      * @test
      */
-    public function testTokenGenerationWithBadAttribute()
+    public function test_withdraw_too_many_ids_returns_bad_request()
     {
+        factory(TwoFAccount::class, 102)->create();
+        $ids = DB::table('twofaccounts')->pluck('id')->implode(',');
+
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/otp', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'totp',
-                'secret' => '',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(422)
+            ->json('PATCH', '/api/v1/twofaccounts/withdraw?ids=' . $ids)
+            ->assertStatus(400)
             ->assertJsonStructure([
-                'errors' => [
-                    'secret'
-                ]
+                'message',
+                'reason',
             ]);
     }
 
 
     /**
-     * test TwoFAccount index fetching via API
-     *
      * @test
      */
-    public function testTwofaccountCount()
+    public function test_destroy_twofaccount_returns_success()
     {
-        $twofaccount = factory(TwoFAccount::class, 3)->create();
+        $twofaccount = factory(TwoFAccount::class)->create();
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/v1/twofaccounts/count')
-            ->assertStatus(200)
-            ->assertJson([
-                'count' => 3
-            ]
-        );
+            ->json('DELETE', '/api/v1/twofaccounts/' . $twofaccount->id)
+            ->assertNoContent();
     }
 
 
     /**
-     * test TwoFAccount deletion via API
-     *
      * @test
      */
-    public function testTwofaccountDeletion()
+    public function test_destroy_missing_twofaccount_returns_not_found()
     {
         $twofaccount = factory(TwoFAccount::class)->create();
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('DELETE', '/api/v1/twofaccounts/' . $twofaccount->id)
-            ->assertStatus(204);
+            ->json('DELETE', '/api/v1/twofaccounts/1000')
+            ->assertNotFound();
     }
 
 
     /**
-     * test TwoFAccounts batch deletion via API
-     *
      * @test
      */
-    public function testTwofaccountBatchDestroy()
+    public function test_batch_destroy_twofaccount_returns_success()
     {
         factory(TwoFAccount::class, 3)->create();
-
-        $ids = \Illuminate\Support\Facades\DB::table('twofaccounts')->value('id');
+        $ids = DB::table('twofaccounts')->pluck('id')->implode(',');
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('DELETE', '/api/v1/twofaccounts/batch', [
-                'data' => $ids])
-            ->assertStatus(204);
+            ->json('DELETE', '/api/v1/twofaccounts?ids=' . $ids)
+            ->assertNoContent();
     }
 
 
     /**
-     * test TwoFAccounts reorder
-     *
      * @test
      */
-    public function testTwofaccountReorder()
+    public function test_batch_destroy_too_many_twofaccounts_returns_bad_request()
     {
-        factory(TwoFAccount::class, 3)->create();
+        factory(TwoFAccount::class, 102)->create();
+        $ids = DB::table('twofaccounts')->pluck('id')->implode(',');
 
         $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/v1/twofaccounts/reorder', [
-                'orderedIds' => [3,2,1]])
-            ->assertStatus(200);
+            ->json('DELETE', '/api/v1/twofaccounts?ids=' . $ids)
+            ->assertStatus(400)
+            ->assertJsonStructure([
+                'message',
+                'reason',
+            ]);
     }
 
-}
+}

+ 7 - 0
tests/Api/v1/Requests/UserPatchPwdRequestTest.php

@@ -47,6 +47,7 @@ class UserPatchPwdRequestTest extends TestCase
             [[
                 'currentPassword' => 'newPassword',
                 'password' => 'newPassword',
+                'password_confirmation' => 'newPassword',
             ]],
         ];
     }
@@ -71,26 +72,32 @@ class UserPatchPwdRequestTest extends TestCase
             [[
                 'currentPassword' => '', // required
                 'password' => 'newPassword',
+                'password_confirmation' => 'newPassword',
             ]],
             [[
                 'currentPassword' => 'currentPassword',
                 'password' => '', // required
+                'password_confirmation' => 'newPassword',
             ]],
             [[
                 'currentPassword' => 'newPassword',
                 'password' => 'anotherPassword', // confirmed
+                'password_confirmation' => 'newPassword',
             ]],
             [[
                 'currentPassword' => 'pwd',
                 'password' => 'pwd', // min:8
+                'password_confirmation' => 'newPassword',
             ]],
             [[
                 'currentPassword' => 'pwd',
                 'password' => true, // string
+                'password_confirmation' => 'newPassword',
             ]],
             [[
                 'currentPassword' => 'pwd',
                 'password' => 10, // string
+                'password_confirmation' => 'newPassword',
             ]],
         ];
     }

+ 0 - 73
tests/Unit/Settings/OptionTest.php

@@ -1,73 +0,0 @@
-<?php
-
-namespace Tests\Unit\Settings;
-
-use App\User;
-use Tests\TestCase;
-
-class OptionTest extends TestCase
-{
-    /** @var \App\User */
-    protected $user;
-
-
-    /**
-     * @test
-     */
-    public function setUp(): void
-    {
-        parent::setUp();
-
-        $this->user = factory(User::class)->create();
-    }
-
-
-    /**
-     * test Settings storage via API
-     *
-     * @test
-     */
-    public function testSettingsStorage()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/settings/options', [
-                    'setting_1' => 'value_1',
-                    'setting_2' => true,
-                    'setting_3' => false,
-                ])
-            ->assertStatus(200)
-            ->assertJson([
-                'message' => __('settings.forms.setting_saved'),
-                'settings' => [
-                    'setting_1' => 'value_1',
-                    'setting_2' => true,
-                    'setting_3' => false,
-                ]
-            ]);
-    }
-
-
-    /**
-     * test Settings list fetching via API
-     *
-     * @test
-     */
-    public function testSettingsIndexListing()
-    {
-        option(['setting_1' => 'value_1']);
-        option(['setting_2' => true]);
-        option(['setting_3' => false]);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/settings/options')
-            ->assertStatus(200)
-            ->assertJson([
-                'settings' => [
-                    'setting_1' => 'value_1',
-                    'setting_2' => true,
-                    'setting_3' => false,
-                ]
-            ]);
-    }
-
-}

+ 0 - 819
tests/Unit/TwoFAccountTest.php

@@ -1,819 +0,0 @@
-<?php
-
-namespace Tests\Unit;
-
-use App\User;
-use Tests\TestCase;
-use App\TwoFAccount;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Storage;
-
-class TwoFAccountTest extends TestCase
-{
-    /** @var \App\User */
-    protected $user;
-
-
-    /**
-     * @test
-     */
-    public function setUp(): void
-    {
-        parent::setUp();
-
-        $this->user = factory(User::class)->create();
-    }
-
-
-    /**
-     * test Totp TwoFAccount display via API
-     *
-     * @test
-     */
-    public function testTotpTwofaccountDisplay()
-    {
-        Storage::put('test.png', 'emptied to prevent missing resource replaced by null by the model getter');
-
-        $twofaccount = factory(TwoFAccount::class)->create([
-            'service' => 'testTOTP',
-            'account' => 'test@test.com',
-            'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
-            'icon' => 'test.png'
-        ]);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/twofaccounts/' . $twofaccount->id)
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'service' => 'testTOTP',
-                'account' => 'test@test.com',
-                'icon' => 'test.png',
-                'group_id' => null,
-                'isConsistent' => true,
-                'otpType' => 'totp',
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'imageLink' => null,
-            ])
-            ->assertJsonMissing([
-                'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'algorithm' => 'sha1',
-            ]);
-    }
-
-
-    /**
-     * test Hotp TwoFAccount display via API
-     *
-     * @test
-     */
-    public function testHotpTwofaccountDisplayWithCounterIncrement()
-    {
-        $twofaccount = factory(TwoFAccount::class)->create([
-            'service' => 'testTOTP',
-            'account' => 'test@test.com',
-            'uri' => 'otpauth://hotp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test&counter=1',
-        ]);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/token', ['id' => $twofaccount->id])
-            ->assertStatus(200);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/twofaccounts/' . $twofaccount->id)
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'service' => 'testTOTP',
-                'account' => 'test@test.com',
-                'group_id' => null,
-                'isConsistent' => true,
-                'otpType' => 'hotp',
-                'digits' => 6,
-                'hotpCounter' => 2,
-                'imageLink' => null,
-            ])
-            ->assertJsonMissing([
-                'uri' => 'otpauth://hotp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'algorithm' => 'sha1',
-            ]);
-    }
-
-
-    /**
-     * test TwoFAccount display via API
-     *
-     * @test
-     */
-    public function testTwofaccountDisplayWithSensitive()
-    {
-        $twofaccount = factory(TwoFAccount::class)->create([
-            'service' => 'testTOTP',
-            'account' => 'test@test.com',
-            'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW',
-        ]);
-
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/twofaccounts/' . $twofaccount->id . '/withSensitive')
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'algorithm' => 'sha1',
-            ]);
-    }
-
-
-    /**
-     * test missing TwoFAccount display via API
-     *
-     * @test
-     */
-    public function testMissingTwofaccountDisplay()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/twofaccounts/1000')
-            ->assertStatus(404);
-    }
-
-
-    /**
-     * test TwoFAccount preview via API
-     *
-     * @test
-     */
-    public function testTwofaccountPreview()
-    {
-        Storage::put('test.png', 'emptied to prevent missing resource replaced by null by the model getter');
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/preview', [
-                'uri' => 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&issuer=service&image=https%3A%2F%2Fen.opensuse.org%2Fimages%2F4%2F44%2FButton-filled-colour.png',
-            ])
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'service' => 'service',
-                'account' => 'account',
-                'uri' => 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&issuer=service&image=https%3A%2F%2Fen.opensuse.org%2Fimages%2F4%2F44%2FButton-filled-colour.png',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'algorithm' => 'sha1',
-                'otpType' => 'totp',
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'hotpCounter' => null,
-                'imageLink' => 'https://en.opensuse.org/images/4/44/Button-filled-colour.png',
-            ])
-            ->assertJsonStructure([
-                'icon'
-            ]);
-    }
-
-
-    /**
-     * test TwoFAccount preview with unreachable image parameter via API
-     *
-     * @test
-     */
-    public function testTwofaccountPreviewWithUnreachableImage()
-    {
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/preview', [
-                'uri' => 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&issuer=service&image=https%3A%2F%2Fen.opensuse.org%2Fimage.png',
-            ])
-            ->assertStatus(200)
-            ->assertJsonMissing([
-                'icon'
-            ]);
-    }
-
-
-    /**
-     * test TwoFAccount creation via API
-     *
-     * @test
-     */
-    public function testTwofaccountCreationSubmittedByQuickForm()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts', [
-                    'service' => 'testCreation',
-                    'account' => 'test@example.org',
-                    'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
-                    'icon' => 'test.png',
-                ])
-            ->assertStatus(201)
-            ->assertJsonFragment([
-                'service' => 'testCreation',
-                'account' => 'test@example.org',
-                'icon' => 'test.png',
-            ])
-            ->assertJsonMissing([
-                'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
-            ]);
-    }
-
-
-    /**
-     * test Twofaccount Creation Submitted By Advanced Form Without Otp Option via API
-     *
-     * @test
-     */
-    public function testTwofaccountCreationSubmittedByAdvancedFormWithoutOtpOption()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts', [
-                    'service' => 'testCreation',
-                    'account' => 'test@example.org',
-                    'icon' => 'test.png',
-                    'secret' => 'A4GRFHVVRBGY7UIW',
-                    'secretIsBase32Encoded' => 1,
-                    'otpType' => 'totp',
-                    'algorithm' => null,
-                    'digits' => null,
-                    'totpPeriod' => null,
-                    'hotpCounter' => null,
-                    'imageLink' => null,
-                ])
-            ->assertStatus(201)
-            ->assertJsonFragment([
-                'service' => 'testCreation',
-                'account' => 'test@example.org',
-                'icon' => 'test.png',
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'hotpCounter' => null,
-                'imageLink' => null,
-            ])
-            ->assertJsonMissing([
-                'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
-                'algorithm' => null,
-                'secret' => 'A4GRFHVVRBGY7UIW',
-            ]);
-    }
-
-
-    /**
-     * test Twofaccount Creation Submitted By Advanced Form with Otp Option via API
-     *
-     * @test
-     */
-    public function testTwofaccountCreationSubmittedByAdvancedFormWithOtpOption()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts', [
-                    'service' => 'testCreation',
-                    'account' => 'test@example.org',
-                    'icon' => 'test.png',
-                    'secret' => 'A4GRFHVVRBGY7UIW',
-                    'secretIsBase32Encoded' => 1,
-                    'otpType' => 'totp',
-                    'algorithm' => 'sha256',
-                    'digits' => 8,
-                    'totpPeriod' => 40,
-                    'hotpCounter' => null,
-                ])
-            ->assertStatus(201)
-            ->assertJsonFragment([
-                'service' => 'testCreation',
-                'account' => 'test@example.org',
-                'icon' => 'test.png',
-                'digits' => 8,
-                'totpPeriod' => 40,
-                'hotpCounter' => null,
-            ])
-            ->assertJsonMissing([
-                'uri' => '',
-                'algorithm' => null,
-                'secret' => 'A4GRFHVVRBGY7UIW',
-            ]);
-    }
-
-
-    /**
-     * test TwoFAccount creation when fiels are empty via API
-     *
-     * @test
-     */
-    public function testTwofaccountCreationWithEmptyRequest()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts', [
-                    'service' => '',
-                    'account' => '',
-                    'uri' => '',
-                    'icon' => '',
-                ])
-            ->assertStatus(422);
-    }
-
-
-    /**
-     * test TwoFAccount creation with an invalid TOTP uri via API
-     *
-     * @test
-     */
-    public function testTwofaccountCreationWithInvalidTotp()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts', [
-                    'service' => 'testCreation',
-                    'account' => 'test@example.org',
-                    'uri' => 'invalidTOTP',
-                    'icon' => 'test.png',
-                ])
-            ->assertStatus(422);
-    }
-
-
-    /**
-     * test show account when uri field remains encrypted via API
-     *
-     * @test
-     */
-    public function testShowAccountWithUndecipheredUri()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts', [
-                    'service' => 'testCreation',
-                    'account' => 'test@example.org',
-                    'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
-                    'icon' => 'test.png',
-                ])
-            ->assertStatus(201);
-
-        DB::table('twofaccounts')
-            ->where('id', 1)
-            ->update([
-                'uri' => '**encrypted**',
-            ]);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/twofaccounts/1')
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'isConsistent' => false,
-            ]);
-    }
-
-
-    /**
-     * test totp  token generation for a given existing account via API
-     *
-     * @test
-     */
-    public function testTotpTokenGenerationWithAccountId()
-    {
-        $twofaccount = factory(TwoFAccount::class)->create([
-            'service' => 'testService',
-            'account' => 'testAccount',
-            'uri' => 'otpauth://totp/testService:testAccount?secret=A4GRFHVVRBGY7UIW&issuer=testService'
-        ]);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/token', ['id' => $twofaccount->id])
-            ->assertStatus(200)
-            ->assertJsonStructure([
-                'token',
-                'totpTimestamp',
-                'totpPeriod',
-            ]);
-    }
-
-
-    /**
-     * test hotp token generation for a given existing account via API
-     *
-     * @test
-     */
-    public function testHotpTokenGenerationWithAccountId()
-    {
-        $twofaccount = factory(TwoFAccount::class)->create([
-            'service' => 'testService',
-            'account' => 'testAccount',
-            'uri' => 'otpauth://hotp/testService:testAccount?secret=A4GRFHVVRBGY7UIW&issuer=testService&counter=1'
-        ]);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/token', ['id' => $twofaccount->id])
-            ->assertStatus(200)
-            ->assertJsonStructure([
-                'token',
-            ]);
-    }
-
-
-    /**
-     * test token generation by providing an URI via API
-     *
-     * @test
-     */
-    public function testTokenGenerationWithUri()
-    {
-        $uri = 'otpauth://totp/service:account?secret=A4GRFHVVRBGY7UIW&issuer=service';
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/token', ['otp' => ['uri' => $uri]])
-            ->assertStatus(200)
-            ->assertJsonStructure([
-                'token',
-                'totpTimestamp',
-                'totpPeriod',
-            ]);
-    }
-
-
-    /**
-     * test totp token generation by providing an array of otp attributes without URI via API
-     *
-     * @test
-     */
-    public function testTotpTokenGenerationWithAttributesArray()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/token', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'totp',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(200)
-            ->assertJsonStructure([
-                'token',
-                'totpTimestamp',
-                'totpPeriod',
-            ]);
-    }
-
-
-    /**
-     * test hotp token generation by providing an array of otp attributes without URI via API
-     *
-     * @test
-     */
-    public function testHotpTokenGenerationWithAttributesArray()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/token', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'hotp',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 6,
-                'hotpCounter' => 1,
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(200)
-            ->assertJsonStructure([
-                'token',
-                'hotpCounter',
-            ]);
-    }
-
-
-    /**
-     * test token generation by providing an array of otp attributes with a bad otp type via API
-     *
-     * @test
-     */
-    public function testTokenGenerationWithBadOtptypeAttribute()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/token', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'otp',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(422)
-            ->assertJsonStructure([
-                'errors' => [
-                    'otpType'
-                ]
-            ]);
-    }
-
-
-    /**
-     * test token generation by providing an array of otp attributes without secret via API
-     *
-     * @test
-     */
-    public function testTokenGenerationWithMissingSecretAttribute()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/token', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'totp',
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 'x',
-                'totpPeriod' => 'y',
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(422)
-            ->assertJsonStructure([
-                'errors' => [
-                    'qrcode'
-                ]
-            ]);
-    }
-
-
-    /**
-     * test token generation by providing an array of bad attributes  via API
-     *
-     * @test
-     */
-    public function testTokenGenerationWithBadAttribute()
-    {
-        $response = $this->actingAs($this->user, 'api')
-            ->json('POST', '/api/twofaccounts/token', ['otp' => [
-                'service' => 'service',
-                'account' => 'account',
-                'otpType' => 'totp',
-                'secret' => '',
-                'secretIsBase32Encoded' => 1,
-                'digits' => 6,
-                'totpPeriod' => 30,
-                'algorithm' => 'sha1',
-                'uri' => ''
-            ]])
-            ->assertStatus(422)
-            ->assertJsonStructure([
-                'errors' => [
-                    'secret'
-                ]
-            ]);
-    }
-
-
-    /**
-     * test TwoFAccount TOTP update via API
-     *
-     * @test
-     */
-    public function testTwofaccountTotpUpdate()
-    {
-        $twofaccount = factory(TwoFAccount::class)->create();
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('PUT', '/api/twofaccounts/' . $twofaccount->id, [
-                    'service' => 'service',
-                    'account' => 'account',
-                    'icon' => 'testUpdate.png',
-                    'otpType' => 'totp',
-                    'secret' => 'A4GRFHVVRBGY7UIW',
-                    'secretIsBase32Encoded' => 1,
-                    'digits' => 8,
-                    'totpPeriod' => 40,
-                    'algorithm' => 'sha256',
-                    'uri' => ''
-                ])
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'id' => 1,
-                'service' => 'service',
-                'account' => 'account',
-                'icon' => 'testUpdate.png',
-                'otpType' => 'totp',
-                'digits' => 8,
-                'totpPeriod' => 40
-            ])
-            ->assertJsonMissing([
-                'uri' => $twofaccount->uri,
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'algorithm' => 'sha256',
-            ]);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/twofaccounts/' . $twofaccount->id . '/withSensitive')
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'secret' => 'A4GRFHVVRBGY7UIW',
-                'algorithm' => 'sha256',
-            ])
-            ->assertJsonStructure([
-                'uri',
-            ]);
-    }
-
-
-    /**
-     * test TwoFAccount HOTP update via API
-     *
-     * @test
-     */
-    public function testTwofaccountHotpUpdate()
-    {
-        $twofaccount = factory(TwoFAccount::class)->create([
-            'service' => 'service',
-            'account' => 'account',
-            'uri' => 'otpauth://hotp/service:account?counter=1&secret=A4GRFHVVRBGY7UIW'
-        ]);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('PUT', '/api/twofaccounts/' . $twofaccount->id, [
-                    'service' => 'testUpdate.com',
-                    'account' => 'testUpdate',
-                    'icon' => 'testUpdate.png',
-                    'otpType' => 'hotp',
-                    'secret' => 'BBBBFFFFEEEEAAAA',
-                    'secretIsBase32Encoded' => 1,
-                    'digits' => 8,
-                    'hotpCounter' => 5,
-                    'algorithm' => 'sha256',
-                    'uri' => ''
-                ])
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'id' => 1,
-                'service' => 'testUpdate.com',
-                'account' => 'testUpdate',
-                'icon' => 'testUpdate.png',
-                'otpType' => 'hotp',
-                'digits' => 8,
-                'hotpCounter' => 5
-            ])
-            ->assertJsonMissing([
-                'uri' => $twofaccount->uri,
-                'secret' => 'BBBBFFFFEEEEAAAA',
-                'algorithm' => 'sha256',
-            ]);
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/twofaccounts/' . $twofaccount->id . '/withSensitive')
-            ->assertStatus(200)
-            ->assertJsonFragment([
-                'secret' => 'BBBBFFFFEEEEAAAA',
-                'algorithm' => 'sha256',
-            ])
-            ->assertJsonStructure([
-                'uri',
-            ]);
-    }
-
-
-    /**
-     * test TwoFAccount update via API
-     *
-     * @test
-     */
-    public function testTwofaccountUpdateOfMissingTwoFAccount()
-    {
-        $twofaccount = factory(TwoFAccount::class)->create();
-        $id = $twofaccount->id;
-        $twofaccount->delete();
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('PUT', '/api/twofaccounts/' . $id, [
-                    'service' => 'testUpdate.com',
-                    'account' => 'testUpdate',
-                    'icon' => 'testUpdate.png',
-                    'otpType' => 'hotp',
-                    'secret' => 'BBBBFFFFEEEEAAAA',
-                    'secretIsBase32Encoded' => 1,
-                    'digits' => 8,
-                    'hotpCounter' => 5,
-                    'algorithm' => 'sha256',
-                    'uri' => '',
-                    'imageLink' => 'http://www.image.net/file.png'
-                ])
-            ->assertStatus(404);
-    }
-
-
-    /**
-     * test TwoFAccount index fetching via API
-     *
-     * @test
-     */
-    public function testTwofaccountIndexListing()
-    {
-        $twofaccount = factory(TwoFAccount::class, 3)->create();
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/twofaccounts')
-            ->assertStatus(200)
-            ->assertJsonCount(3, $key = null)
-            ->assertJsonStructure([
-                '*' => [
-                    'id',
-                    'service',
-                    'account',
-                    'icon',
-                    'isConsistent',
-                    'order_column',
-                    'group_id',
-                    'otpType'
-                ]
-            ]
-        );
-    }
-
-
-    /**
-     * test TwoFAccount index fetching via API
-     *
-     * @test
-     */
-    public function testTwofaccountCount()
-    {
-        $twofaccount = factory(TwoFAccount::class, 3)->create();
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/twofaccounts/count')
-            ->assertStatus(200)
-            ->assertJson([
-                'count' => 3
-            ]
-        );
-    }
-
-
-    /**
-     * test TwoFAccount deletion via API
-     *
-     * @test
-     */
-    public function testTwofaccountDeletion()
-    {
-        $twofaccount = factory(TwoFAccount::class)->create();
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('DELETE', '/api/twofaccounts/' . $twofaccount->id)
-            ->assertStatus(204);
-    }
-
-
-    /**
-     * test TwoFAccounts batch deletion via API
-     *
-     * @test
-     */
-    public function testTwofaccountBatchDestroy()
-    {
-        factory(TwoFAccount::class, 3)->create();
-
-        $ids = \Illuminate\Support\Facades\DB::table('twofaccounts')->value('id');
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('DELETE', '/api/twofaccounts/batch', [
-                'data' => $ids])
-            ->assertStatus(204);
-    }
-
-
-    /**
-     * test TwoFAccounts reorder
-     *
-     * @test
-     */
-    public function testTwofaccountReorder()
-    {
-        factory(TwoFAccount::class, 3)->create();
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('PATCH', '/api/twofaccounts/reorder', [
-                'orderedIds' => [3,2,1]])
-            ->assertStatus(200);
-    }
-
-
-    /**
-     * test show QR code via API
-     *
-     * @test
-     */
-    public function testShowQrcode()
-    {
-
-        $twofaccount = factory(TwoFAccount::class)->create();
-
-        $response = $this->actingAs($this->user, 'api')
-            ->json('GET', '/api/qrcode/' . $twofaccount->id)
-            ->assertJsonStructure([
-                'qrcode',
-            ])
-            ->assertStatus(200);
-            
-            $this->assertStringStartsWith('data:image/png;base64', $response->getData()->qrcode);
-    }
-
-}