diff --git a/tests/Api/v1/Controllers/GroupControllerTest.php b/tests/Api/v1/Controllers/GroupControllerTest.php index c322eb90..c97fca82 100644 --- a/tests/Api/v1/Controllers/GroupControllerTest.php +++ b/tests/Api/v1/Controllers/GroupControllerTest.php @@ -126,8 +126,8 @@ public function test_update_returns_updated_group_resource() $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 @@ public function test_update_missing_group_returns_not_found() { $response = $this->actingAs($this->user, 'api') ->json('PUT', '/api/v1/groups/1000', [ - 'name' => 'testUpdate', - ]) + 'name' => 'testUpdate', + ]) ->assertNotFound() ->assertJsonStructure([ 'message' @@ -162,8 +162,8 @@ public function test_update_with_invalid_data_returns_validation_error() $response = $this->actingAs($this->user, 'api') ->json('PUT', '/api/v1/groups/' . $group->id, [ - 'name' => null, - ]) + 'name' => null, + ]) ->assertStatus(422); } @@ -178,8 +178,8 @@ public function test_assign_accounts_returns_updated_group_resource() $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 @@ public function test_assign_accounts_to_missing_group_returns_not_found() $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 @@ public function test_assign_invalid_accounts_returns_validation_error() $response = $this->actingAs($this->user, 'api') ->json('POST', '/api/v1/groups/' . $group->id . '/assign', [ - 'ids' => 1, - ]) + 'ids' => 1, + ]) ->assertStatus(422); } @@ -233,7 +233,7 @@ public function test_get_assigned_accounts_returns_twofaccounts_collection() $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 @@ public function test_get_assigned_accounts_returns_twofaccounts_collection_with_ $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') diff --git a/tests/Api/v1/Controllers/IconControllerTest.php b/tests/Api/v1/Controllers/IconControllerTest.php index b29344f8..36ca8047 100644 --- a/tests/Api/v1/Controllers/IconControllerTest.php +++ b/tests/Api/v1/Controllers/IconControllerTest.php @@ -20,8 +20,8 @@ public function test_upload_icon_returns_filename() $file = UploadedFile::fake()->image('testIcon.jpg'); $response = $this->json('POST', '/api/v1/icons', [ - 'icon' => $file, - ]) + 'icon' => $file, + ]) ->assertCreated() ->assertJsonStructure([ 'filename' @@ -35,8 +35,8 @@ public function test_upload_icon_returns_filename() public function test_upload_with_invalid_data_returns_validation_error() { $response = $this->json('POST', '/api/v1/icons', [ - 'icon' => null, - ]) + 'icon' => null, + ]) ->assertStatus(422); } diff --git a/tests/Api/v1/Controllers/QrcodeControllerTest.php b/tests/Api/v1/Controllers/QrcodeControllerTest.php index 1f3c5168..acdc12c5 100644 --- a/tests/Api/v1/Controllers/QrcodeControllerTest.php +++ b/tests/Api/v1/Controllers/QrcodeControllerTest.php @@ -93,11 +93,10 @@ public function test_decode_qrcode_return_success() */ 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); } diff --git a/tests/Api/v1/Controllers/SettingControllerTest.php b/tests/Api/v1/Controllers/SettingControllerTest.php new file mode 100644 index 00000000..8206268f --- /dev/null +++ b/tests/Api/v1/Controllers/SettingControllerTest.php @@ -0,0 +1,261 @@ +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(); + } + + +} \ No newline at end of file diff --git a/tests/Api/v1/Controllers/TwoFAccountControllerTest.php b/tests/Api/v1/Controllers/TwoFAccountControllerTest.php index 19b244bb..ec6820d0 100644 --- a/tests/Api/v1/Controllers/TwoFAccountControllerTest.php +++ b/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 @@ public function setUp(): void */ 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 @@ public function test_index_returns_twofaccount_collection() */ 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 @@ public function test_show_twofaccount_returns_twofaccount_resource_without_secre $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 @@ public function test_store_returns_success_with_consistent_resource_structure(ar $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 @@ public function provideDataForTestStoreStructure() : array [[ '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 @@ public function test_store_totp_using_fully_custom_uri_returns_consistent_resour { $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 @@ public function test_store_totp_using_short_uri_returns_resource_with_default_ot { $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 @@ public function test_store_totp_using_short_uri_returns_resource_with_default_ot 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 @@ public function test_store_totp_using_fully_custom_parameters_returns_consistent 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 @@ public function test_store_hotp_using_fully_custom_uri_returns_consistent_resour { $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 @@ public function test_store_hotp_using_short_uri_returns_resource_with_default_ot { $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 @@ public function test_store_hotp_using_short_uri_returns_resource_with_default_ot 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 @@ public function test_store_hotp_using_fully_custom_parameters_returns_consistent 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 @@ public function test_store_with_invalid_uri_returns_validation_error() { $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 @@ public function test_update_totp_returns_success_with_updated_resource() $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 @@ public function test_update_hotp_returns_success_with_updated_resource() $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 @@ public function test_update_hotp_returns_success_with_updated_resource() 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 @@ public function test_update_twofaccount_with_invalid_data_returns_validation_err $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 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/v1/twofaccounts/otp', ['id' => $twofaccount->id]) - ->assertStatus(200); - - $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, - ]) - ->assertJsonMissing([ - 'uri' => 'otpauth://hotp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test', - 'secret' => 'A4GRFHVVRBGY7UIW', - 'algorithm' => 'sha1', - ]); - } - - - /** - * 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/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) - ->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/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' - ]); - } - - - /** - * test show account when uri field remains encrypted via API - * - * @test - */ - public function testShowAccountWithUndecipheredUri() - { - $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**', - ]); - - $response = $this->actingAs($this->user, 'api') - ->json('GET', '/api/v1/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/v1/twofaccounts/otp', ['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/v1/twofaccounts/otp', ['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/v1/twofaccounts/otp', ['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/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', - ]); - } - - - /** - * 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/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', - ]); - } - - - /** - * 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/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' - ] - ]); - } - - - /** - * 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/v1/twofaccounts/otp', ['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/v1/twofaccounts/otp', ['otp' => [ - 'service' => 'service', - 'account' => 'account', - 'otpType' => 'totp', - 'secret' => '', - 'secretIsBase32Encoded' => 1, - 'digits' => 6, - 'totpPeriod' => 30, - 'algorithm' => 'sha1', - 'uri' => '' - ]]) - ->assertStatus(422) - ->assertJsonStructure([ - 'errors' => [ - 'secret' - ] - ]); - } - - - /** - * 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/v1/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/v1/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/v1/twofaccounts/batch', [ - 'data' => $ids]) - ->assertStatus(204); - } - - - /** - * test TwoFAccounts reorder - * - * @test - */ - public function testTwofaccountReorder() + 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); + ->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 + */ + public function test_get_otp_using_totp_twofaccount_id_returns_consistent_resource() + { + $twofaccount = factory(TwoFAccount::class)->create([ + '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('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('POST', '/api/v1/twofaccounts/otp', [ + 'uri' => self::TOTP_FULL_CUSTOM_URI, + ]) + ->assertOk() + ->assertJsonStructure(self::VALID_OTP_RESOURCE_STRUCTURE_FOR_TOTP) + ->assertJsonFragment([ + 'otp_type' => 'totp', + 'period' => self::PERIOD_CUSTOM, + ]); + } + + + /** + * @test + */ + public function test_get_otp_by_posting_totp_parameters_returns_consistent_resource() + { + $response = $this->actingAs($this->user, 'api') + ->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([ + 'otp_type' => 'totp', + 'period' => self::PERIOD_CUSTOM, + ]); + } + + + /** + * @test + */ + 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('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 + */ + public function test_get_otp_by_posting_hotp_uri_returns_consistent_resource() + { + $response = $this->actingAs($this->user, 'api') + ->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('POST', '/api/v1/twofaccounts/otp', self::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP) + ->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_multiple_inputs_returns_bad_request() + { + $response = $this->actingAs($this->user, 'api') + ->json('POST', '/api/v1/twofaccounts/otp', [ + 'uri' => self::HOTP_FULL_CUSTOM_URI, + 'key' => 'value', + ]) + ->assertStatus(400) + ->assertJsonStructure([ + 'message', + 'reason', + ]); + } + + + /** + * @test + */ + public function test_get_otp_using_indecipherable_twofaccount_id_returns_bad_request() + { + $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('GET', '/api/v1/twofaccounts/' . $twofaccount->id . '/otp') + ->assertStatus(400) + ->assertJsonStructure([ + 'message', + ]); + } + + + /** + * @test + */ + public function test_get_otp_using_missing_twofaccount_id_returns_not_found() + { + $response = $this->actingAs($this->user, 'api') + ->json('GET', '/api/v1/twofaccounts/1000/otp') + ->assertNotFound(); + } + + + /** + * @test + */ + public function test_get_otp_by_posting_invalid_uri_returns_validation_error() + { + $response = $this->actingAs($this->user, 'api') + ->json('POST', '/api/v1/twofaccounts/otp', [ + 'uri' => self::INVALID_OTPAUTH_URI, + ]) + ->assertStatus(422); + } + + + /** + * @test + */ + public function test_get_otp_by_posting_invalid_parameters_returns_validation_error() + { + $response = $this->actingAs($this->user, 'api') + ->json('POST', '/api/v1/twofaccounts/otp', self::ARRAY_OF_INVALID_PARAMETERS) + ->assertStatus(422); + } + + + /** + * @test + */ + public function test_count_returns_right_number_of_twofaccount() + { + factory(TwoFAccount::class, 3)->create(); + + $response = $this->actingAs($this->user, 'api') + ->json('GET', '/api/v1/twofaccounts/count') + ->assertStatus(200) + ->assertExactJson([ + 'count' => 3 + ]); + } + + + /** + * @test + */ + 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('PATCH', '/api/v1/twofaccounts/withdraw?ids=1,2,3' . $ids) + ->assertOk() + ->assertJsonStructure([ + 'message', + ]); + } + + + /** + * @test + */ + 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('PATCH', '/api/v1/twofaccounts/withdraw?ids=' . $ids) + ->assertStatus(400) + ->assertJsonStructure([ + 'message', + 'reason', + ]); + } + + + /** + * @test + */ + public function test_destroy_twofaccount_returns_success() + { + $twofaccount = factory(TwoFAccount::class)->create(); + + $response = $this->actingAs($this->user, 'api') + ->json('DELETE', '/api/v1/twofaccounts/' . $twofaccount->id) + ->assertNoContent(); + } + + + /** + * @test + */ + 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/1000') + ->assertNotFound(); + } + + + /** + * @test + */ + public function test_batch_destroy_twofaccount_returns_success() + { + factory(TwoFAccount::class, 3)->create(); + $ids = DB::table('twofaccounts')->pluck('id')->implode(','); + + $response = $this->actingAs($this->user, 'api') + ->json('DELETE', '/api/v1/twofaccounts?ids=' . $ids) + ->assertNoContent(); + } + + + /** + * @test + */ + public function test_batch_destroy_too_many_twofaccounts_returns_bad_request() + { + factory(TwoFAccount::class, 102)->create(); + $ids = DB::table('twofaccounts')->pluck('id')->implode(','); + + $response = $this->actingAs($this->user, 'api') + ->json('DELETE', '/api/v1/twofaccounts?ids=' . $ids) + ->assertStatus(400) + ->assertJsonStructure([ + 'message', + 'reason', + ]); + } + +} \ No newline at end of file diff --git a/tests/Api/v1/Requests/UserPatchPwdRequestTest.php b/tests/Api/v1/Requests/UserPatchPwdRequestTest.php index b81d94ea..0ce2592c 100644 --- a/tests/Api/v1/Requests/UserPatchPwdRequestTest.php +++ b/tests/Api/v1/Requests/UserPatchPwdRequestTest.php @@ -47,6 +47,7 @@ public function provideValidData() : array [[ 'currentPassword' => 'newPassword', 'password' => 'newPassword', + 'password_confirmation' => 'newPassword', ]], ]; } @@ -71,26 +72,32 @@ public function provideInvalidData() : array [[ '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', ]], ]; } diff --git a/tests/Unit/Settings/OptionTest.php b/tests/Unit/Settings/OptionTest.php deleted file mode 100644 index 3b8ca4d6..00000000 --- a/tests/Unit/Settings/OptionTest.php +++ /dev/null @@ -1,73 +0,0 @@ -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, - ] - ]); - } - -} diff --git a/tests/Unit/TwoFAccountTest.php b/tests/Unit/TwoFAccountTest.php deleted file mode 100644 index b6e1c90d..00000000 --- a/tests/Unit/TwoFAccountTest.php +++ /dev/null @@ -1,819 +0,0 @@ -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); - } - -}