diff --git a/app/Services/LogoLib/AbstractLogoLib.php b/app/Services/LogoLib/AbstractLogoLib.php index 246d45d9..458a935d 100644 --- a/app/Services/LogoLib/AbstractLogoLib.php +++ b/app/Services/LogoLib/AbstractLogoLib.php @@ -139,10 +139,9 @@ abstract class AbstractLogoLib implements LogoLibInterface $url = $this->logoUrl($logoFilename); try { - // $response = Http::withOptions([ - // 'proxy' => config('2fauth.config.outgoingProxy'), - // ])->retry(3, 100)->get($url); - $response = Http::get($url); + $response = Http::withOptions([ + 'proxy' => config('2fauth.config.outgoingProxy'), + ])->retry(3, 100)->get($url); if ($response->successful()) { $filename = $this->cachePrefix . $logoFilename; diff --git a/tests/Api/v1/Controllers/IconControllerTest.php b/tests/Api/v1/Controllers/IconControllerTest.php index 07312366..6722e632 100644 --- a/tests/Api/v1/Controllers/IconControllerTest.php +++ b/tests/Api/v1/Controllers/IconControllerTest.php @@ -6,13 +6,11 @@ use App\Api\v1\Controllers\IconController; use App\Facades\IconStore; use App\Models\TwoFAccount; use App\Models\User; -use App\Services\LogoLib\TfaLogoLib; use Illuminate\Http\Testing\FileFactory; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Storage; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\DataProviderExternal; use PHPUnit\Framework\Attributes\Test; use Tests\Classes\LocalFile; use Tests\Data\CommonDataProvider; @@ -39,12 +37,6 @@ class IconControllerTest extends FeatureTestCase Storage::fake('logos'); Http::preventStrayRequests(); - Http::fake([ - 'https://raw.githubusercontent.com/2factorauth/twofactorauth/master/img/*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - 'https://cdn.jsdelivr.net/gh/selfhst/icons/*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - 'https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - TfalogoLib::TFA_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), - ]); Http::fake([ OtpTestData::EXTERNAL_IMAGE_URL_DECODED => Http::response((new FileFactory)->image('file.png', 10, 10)->tempFile, 200), ]); @@ -105,13 +97,15 @@ class IconControllerTest extends FeatureTestCase } #[Test] - #[DataProviderExternal(CommonDataProvider::class, 'iconsCollectionProvider')] - public function test_fetch_logo_returns_filename($iconCollection) + public function test_fetch_logo_returns_filename() { + Http::fake([ + CommonDataProvider::SELFH_URL => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), + ]); + $response = $this->actingAs($this->user, 'api-guard') ->json('POST', '/api/v1/icons/default', [ 'service' => 'service', - 'iconCollection' => $iconCollection, ]) ->assertStatus(201) ->assertJsonStructure([ @@ -120,12 +114,50 @@ class IconControllerTest extends FeatureTestCase } #[Test] - public function test_fetch_logo_with_infected_svg_data_stores_sanitized_svg_content() + public function test_fetch_logo_using_specified_icon_collection_returns_filename() + { + Http::fake([ + CommonDataProvider::SELFH_URL => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), + CommonDataProvider::DASHBOARDICONS_URL => Http::response(OtpTestData::ICON_SVG_DATA, 200), + ]); + + $response = $this->actingAs($this->user, 'api-guard') + ->json('POST', '/api/v1/icons/default', [ + 'service' => 'service', + 'iconCollection' => 'dashboardicons', + ]) + ->assertStatus(201) + ->assertJsonStructure([ + 'filename', + ]); + + // Don't know why but 'getData()->filename' has some unwanted spaces in it so we trim them + $svgContent = trim(str_replace('> <', '><', IconStore::get($response->getData()->filename))); + + $this->assertEquals(OtpTestData::ICON_SVG_DATA, $svgContent); + } + + #[Test] + public function test_fetch_logo_return_validation_error() { + $response = $this->actingAs($this->user, 'api-guard') + ->json('POST', '/api/v1/icons/default', [ + 'service' => 'service', + 'iconCollection' => 'not_a_valid_icon_collection', + ]) + ->assertStatus(422); + } + + #[Test] + public function test_fetch_logo_with_infected_svg_data_stores_sanitized_svg_content() + { + Http::fake([ + CommonDataProvider::SELFH_URL => Http::response(OtpTestData::ICON_SVG_DATA_INFECTED, 200), + ]); + $response = $this->actingAs($this->user, 'api-guard') ->json('POST', '/api/v1/icons/default', [ 'service' => 'service', - 'iconCollection' => 'tfa', ]) ->assertStatus(201) ->assertJsonStructure([ @@ -139,9 +171,13 @@ class IconControllerTest extends FeatureTestCase #[Test] public function test_fetch_unknown_logo_returns_nothing() { + Http::fake([ + CommonDataProvider::SELFH_URL => Http::response('not found', 404), + ]); + $response = $this->actingAs($this->user, 'api-guard') ->json('POST', '/api/v1/icons/default', [ - 'service' => 'unknown_company', + 'service' => 'NameOfAnUnknownServiceForSure', ]) ->assertNoContent(); } diff --git a/tests/Api/v1/Controllers/TwoFAccountControllerTest.php b/tests/Api/v1/Controllers/TwoFAccountControllerTest.php index 5436fb68..0a14bac8 100644 --- a/tests/Api/v1/Controllers/TwoFAccountControllerTest.php +++ b/tests/Api/v1/Controllers/TwoFAccountControllerTest.php @@ -25,6 +25,7 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use Tests\Classes\LocalFile; +use Tests\Data\CommonDataProvider; use Tests\Data\HttpRequestTestData; use Tests\Data\MigrationTestData; use Tests\Data\OtpTestData; @@ -242,8 +243,8 @@ class TwoFAccountControllerTest extends FeatureTestCase Http::preventStrayRequests(); Http::fake([ - TfaLogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - TfaLogoLib::TFA_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), + CommonDataProvider::TFA_URL => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), + TfaLogoLib::TFA_JSON_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), OtpTestData::EXTERNAL_IMAGE_URL_DECODED => Http::response((new FileFactory)->image('file.png', 10, 10)->tempFile, 200), OtpTestData::EXTERNAL_INFECTED_IMAGE_URL_DECODED => Http::response((new FileFactory)->createWithContent('infected.svg', OtpTestData::ICON_SVG_DATA_INFECTED)->tempFile, 200), 'example.com/*' => Http::response(null, 400), diff --git a/tests/Api/v1/Requests/GroupAssignRequestTest.php b/tests/Api/v1/Requests/GroupAssignRequestTest.php index d212d729..f58d97e4 100644 --- a/tests/Api/v1/Requests/GroupAssignRequestTest.php +++ b/tests/Api/v1/Requests/GroupAssignRequestTest.php @@ -35,7 +35,9 @@ class GroupAssignRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new GroupAssignRequest; + $request = new GroupAssignRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -59,7 +61,9 @@ class GroupAssignRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new GroupAssignRequest; + $request = new GroupAssignRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/IconFetchRequestTest.php b/tests/Api/v1/Requests/IconFetchRequestTest.php index 2157461a..fbcf9e52 100644 --- a/tests/Api/v1/Requests/IconFetchRequestTest.php +++ b/tests/Api/v1/Requests/IconFetchRequestTest.php @@ -35,7 +35,9 @@ class IconFetchRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new IconFetchRequest; + $request = new IconFetchRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -47,15 +49,59 @@ class IconFetchRequestTest extends TestCase public static function provideValidData() : array { return [ - [[ + 'VALID_SERVICE_AS_STRING' => [[ 'service' => 'validWord', ]], - [[ - 'service' => '0', - ]], - [[ + 'VALID_SERVCE_WITH_SPECIAL_CHARS' => [[ 'service' => '~string.with-sp3ci@l-ch4rs', ]], + 'VALID_SELFH_ICON_COLLECTION' => [[ + 'service' => 'validWord', + 'iconCollection' => 'selfh', + ]], + 'VALID_DASHBOARDICONS_ICON_COLLECTION' => [[ + 'service' => 'validWord', + 'iconCollection' => 'dashboardicons', + ]], + 'VALID_TFA_ICON_COLLECTION' => [[ + 'service' => 'validWord', + 'iconCollection' => 'tfa', + ]], + 'VALID_SELFH_ICON_COLLECTION_WITH_VALID_REGULAR_VARIANT' => [[ + 'service' => 'validWord', + 'iconCollection' => 'selfh', + 'variant' => 'regular', + ]], + 'VALID_SELFH_ICON_COLLECTION_WITH_VALID_LIGHT_VARIANT' => [[ + 'service' => 'validWord', + 'iconCollection' => 'selfh', + 'variant' => 'light', + ]], + 'VALID_SELFH_ICON_COLLECTION_WITH_VALID_DARK_VARIANT' => [[ + 'service' => 'validWord', + 'iconCollection' => 'selfh', + 'variant' => 'dark', + ]], + 'VALID_DASHBOARDICONS_ICON_COLLECTION_WITH_VALID_REGULAR_VARIANT' => [[ + 'service' => 'validWord', + 'iconCollection' => 'dashboardicons', + 'variant' => 'regular', + ]], + 'VALID_DASHBOARDICONS_ICON_COLLECTION_WITH_VALID_LIGHT_VARIANT' => [[ + 'service' => 'validWord', + 'iconCollection' => 'dashboardicons', + 'variant' => 'light', + ]], + 'VALID_DASHBOARDICONS_ICON_COLLECTION_WITH_VALID_DARK_VARIANT' => [[ + 'service' => 'validWord', + 'iconCollection' => 'dashboardicons', + 'variant' => 'dark', + ]], + 'VALID_TFA_ICON_COLLECTION_WITH_VALID_REGULAR_VARIANT' => [[ + 'service' => 'validWord', + 'iconCollection' => 'tfa', + 'variant' => 'regular', + ]], ]; } @@ -63,7 +109,9 @@ class IconFetchRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new IconFetchRequest; + $request = new IconFetchRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); @@ -75,18 +123,55 @@ class IconFetchRequestTest extends TestCase public static function provideInvalidData() : array { return [ - [[ + 'NULL_SERVICE' => [[ 'service' => null, ]], - [[ + 'NULL_ICON_COLLECTION' => [[ + 'service' => 'validWord', + 'iconCollection' => null, + ]], + 'NULL_VARIANT' => [[ + 'service' => 'validWord', + 'iconCollection' => 'tfa', + 'variant' => null, + ]], + 'EMPTY_ICON_COLLECTION' => [[ + 'service' => 'validWord', + 'iconCollection' => '', + ]], + 'EMPTY_VARIANT' => [[ + 'service' => 'validWord', + 'iconCollection' => 'tfa', + 'variant' => '', + ]], + 'SERVICE_AS_INT' => [[ 'service' => 0, ]], - [[ + 'SERVICE_AS_BOOL' => [[ 'service' => true, ]], - [[ + 'SERVICE_AS_ARRAY' => [[ 'service' => [], ]], + 'NOT_IN_ICON_COLLECTION_LIST' => [[ + 'service' => 'validWord', + 'iconCollection' => 'string_not_in_icon_collection_list', + ]], + 'NOT_IN_SELFH_VARIANT_LIST' => [[ + 'service' => 'validWord', + 'iconCollection' => 'selfh', + 'variant' => 'string_not_in_selfh_variant_list', + ]], + 'NOT_IN_DASHBOARDICONS_VARIANT_LIST' => [[ + 'service' => 'validWord', + 'iconCollection' => 'dashboardicons', + 'variant' => 'string_not_in_dashboardicons_variant_list', + ]], + 'NOT_IN_TFA_VARIANT_LIST' => [[ + 'service' => 'validWord', + 'iconCollection' => 'tfa', + 'variant' => 'string_not_in_tfa_variant_list', + ]], ]; } } diff --git a/tests/Api/v1/Requests/QrCodeDecodeRequestTest.php b/tests/Api/v1/Requests/QrCodeDecodeRequestTest.php index 4180037e..2713c247 100644 --- a/tests/Api/v1/Requests/QrCodeDecodeRequestTest.php +++ b/tests/Api/v1/Requests/QrCodeDecodeRequestTest.php @@ -36,7 +36,9 @@ class QrCodeDecodeRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new QrCodeDecodeRequest; + $request = new QrCodeDecodeRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -60,7 +62,9 @@ class QrCodeDecodeRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new QrCodeDecodeRequest; + $request = new QrCodeDecodeRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/SettingStoreRequestTest.php b/tests/Api/v1/Requests/SettingStoreRequestTest.php index ccb87e9d..a009feeb 100644 --- a/tests/Api/v1/Requests/SettingStoreRequestTest.php +++ b/tests/Api/v1/Requests/SettingStoreRequestTest.php @@ -38,7 +38,9 @@ class SettingStoreRequestTest extends FeatureTestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new SettingStoreRequest; + $request = new SettingStoreRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -71,7 +73,9 @@ class SettingStoreRequestTest extends FeatureTestCase { Settings::set(self::UNIQUE_KEY, 'uniqueValue'); - $request = new SettingStoreRequest; + $request = new SettingStoreRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/SettingUpdateRequestTest.php b/tests/Api/v1/Requests/SettingUpdateRequestTest.php index 29d51490..a7808e89 100644 --- a/tests/Api/v1/Requests/SettingUpdateRequestTest.php +++ b/tests/Api/v1/Requests/SettingUpdateRequestTest.php @@ -35,7 +35,9 @@ class SettingUpdateRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new SettingUpdateRequest; + $request = new SettingUpdateRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -63,7 +65,9 @@ class SettingUpdateRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new SettingUpdateRequest; + $request = new SettingUpdateRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/TwoFAccountBatchRequestTest.php b/tests/Api/v1/Requests/TwoFAccountBatchRequestTest.php index a9b07d37..24e182e1 100644 --- a/tests/Api/v1/Requests/TwoFAccountBatchRequestTest.php +++ b/tests/Api/v1/Requests/TwoFAccountBatchRequestTest.php @@ -36,7 +36,9 @@ class TwoFAccountBatchRequestTest extends TestCase #[DataProviderExternal(TwoFAccountDataProvider::class, 'validIdsProvider')] public function test_valid_data(array $data) : void { - $request = new TwoFAccountBatchRequest; + $request = new TwoFAccountBatchRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -46,7 +48,9 @@ class TwoFAccountBatchRequestTest extends TestCase #[DataProviderExternal(TwoFAccountDataProvider::class, 'invalidIdsProvider')] public function test_invalid_data(array $data) : void { - $request = new TwoFAccountBatchRequest; + $request = new TwoFAccountBatchRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/TwoFAccountExportRequestTest.php b/tests/Api/v1/Requests/TwoFAccountExportRequestTest.php index 112b405f..cf9a20bd 100644 --- a/tests/Api/v1/Requests/TwoFAccountExportRequestTest.php +++ b/tests/Api/v1/Requests/TwoFAccountExportRequestTest.php @@ -35,7 +35,9 @@ class TwoFAccountExportRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new TwoFAccountExportRequest; + $request = new TwoFAccountExportRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -81,7 +83,9 @@ class TwoFAccountExportRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new TwoFAccountExportRequest; + $request = new TwoFAccountExportRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/TwoFAccountImportRequestTest.php b/tests/Api/v1/Requests/TwoFAccountImportRequestTest.php index 7684ed49..3d3e105f 100644 --- a/tests/Api/v1/Requests/TwoFAccountImportRequestTest.php +++ b/tests/Api/v1/Requests/TwoFAccountImportRequestTest.php @@ -35,7 +35,9 @@ class TwoFAccountImportRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new TwoFAccountImportRequest; + $request = new TwoFAccountImportRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -57,7 +59,9 @@ class TwoFAccountImportRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new TwoFAccountImportRequest; + $request = new TwoFAccountImportRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/TwoFAccountIndexRequestTest.php b/tests/Api/v1/Requests/TwoFAccountIndexRequestTest.php index 908aba54..f43d5917 100644 --- a/tests/Api/v1/Requests/TwoFAccountIndexRequestTest.php +++ b/tests/Api/v1/Requests/TwoFAccountIndexRequestTest.php @@ -36,7 +36,9 @@ class TwoFAccountIndexRequestTest extends TestCase #[DataProviderExternal(TwoFAccountDataProvider::class, 'validIdsProvider')] public function test_valid_data(array $data) : void { - $request = new TwoFAccountIndexRequest; + $request = new TwoFAccountIndexRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -46,7 +48,9 @@ class TwoFAccountIndexRequestTest extends TestCase #[DataProviderExternal(TwoFAccountDataProvider::class, 'invalidIdsProvider')] public function test_invalid_data(array $data) : void { - $request = new TwoFAccountIndexRequest; + $request = new TwoFAccountIndexRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/TwoFAccountReorderRequestTest.php b/tests/Api/v1/Requests/TwoFAccountReorderRequestTest.php index ea5c7946..97f78f67 100644 --- a/tests/Api/v1/Requests/TwoFAccountReorderRequestTest.php +++ b/tests/Api/v1/Requests/TwoFAccountReorderRequestTest.php @@ -35,7 +35,9 @@ class TwoFAccountReorderRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new TwoFAccountReorderRequest; + $request = new TwoFAccountReorderRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -60,7 +62,9 @@ class TwoFAccountReorderRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new TwoFAccountReorderRequest; + $request = new TwoFAccountReorderRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/TwoFAccountStoreRequestTest.php b/tests/Api/v1/Requests/TwoFAccountStoreRequestTest.php index 1a0360d4..f8062717 100644 --- a/tests/Api/v1/Requests/TwoFAccountStoreRequestTest.php +++ b/tests/Api/v1/Requests/TwoFAccountStoreRequestTest.php @@ -37,7 +37,9 @@ class TwoFAccountStoreRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new TwoFAccountStoreRequest; + $request = new TwoFAccountStoreRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -111,7 +113,9 @@ class TwoFAccountStoreRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new TwoFAccountStoreRequest; + $request = new TwoFAccountStoreRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/TwoFAccountUpdateRequestTest.php b/tests/Api/v1/Requests/TwoFAccountUpdateRequestTest.php index 4d7e6f47..e8eb35f4 100644 --- a/tests/Api/v1/Requests/TwoFAccountUpdateRequestTest.php +++ b/tests/Api/v1/Requests/TwoFAccountUpdateRequestTest.php @@ -37,7 +37,9 @@ class TwoFAccountUpdateRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new TwoFAccountUpdateRequest; + $request = new TwoFAccountUpdateRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -87,7 +89,9 @@ class TwoFAccountUpdateRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new TwoFAccountUpdateRequest; + $request = new TwoFAccountUpdateRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/TwoFAccountUriRequestTest.php b/tests/Api/v1/Requests/TwoFAccountUriRequestTest.php index c592ae12..6cde0426 100644 --- a/tests/Api/v1/Requests/TwoFAccountUriRequestTest.php +++ b/tests/Api/v1/Requests/TwoFAccountUriRequestTest.php @@ -35,7 +35,9 @@ class TwoFAccountUriRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new TwoFAccountUriRequest; + $request = new TwoFAccountUriRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -64,7 +66,9 @@ class TwoFAccountUriRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new TwoFAccountUriRequest; + $request = new TwoFAccountUriRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/UserManagerPromoteRequestTest.php b/tests/Api/v1/Requests/UserManagerPromoteRequestTest.php index db3b45eb..3f730d17 100644 --- a/tests/Api/v1/Requests/UserManagerPromoteRequestTest.php +++ b/tests/Api/v1/Requests/UserManagerPromoteRequestTest.php @@ -35,7 +35,9 @@ class UserManagerPromoteRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new UserManagerPromoteRequest; + $request = new UserManagerPromoteRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -66,7 +68,9 @@ class UserManagerPromoteRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new UserManagerPromoteRequest; + $request = new UserManagerPromoteRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Api/v1/Requests/UserManagerStoreRequestTest.php b/tests/Api/v1/Requests/UserManagerStoreRequestTest.php index 4520bd91..c3b75e00 100644 --- a/tests/Api/v1/Requests/UserManagerStoreRequestTest.php +++ b/tests/Api/v1/Requests/UserManagerStoreRequestTest.php @@ -41,7 +41,9 @@ class UserManagerStoreRequestTest extends FeatureTestCase 'email' => 'jane@example.com', ]); - $request = new UserManagerStoreRequest; + $request = new UserManagerStoreRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -79,7 +81,9 @@ class UserManagerStoreRequestTest extends FeatureTestCase 'email' => 'john@example.com', ]); - $request = new UserManagerStoreRequest; + $request = new UserManagerStoreRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Data/CommonDataProvider.php b/tests/Data/CommonDataProvider.php index 9fca95dd..1749a62c 100644 --- a/tests/Data/CommonDataProvider.php +++ b/tests/Data/CommonDataProvider.php @@ -4,20 +4,34 @@ declare(strict_types=1); namespace Tests\Data; +use App\Services\LogoLib\DashboardiconsLogoLib; +use App\Services\LogoLib\SelfhLogoLib; +use App\Services\LogoLib\TfaLogoLib; + final class CommonDataProvider { + const TFA_URL = 'https://raw.githubusercontent.com/2factorauth/twofactorauth/master/img/*'; + const SELFH_URL_ROOT = 'https://cdn.jsdelivr.net/gh/selfhst/icons/'; + const SELFH_URL = self::SELFH_URL_ROOT . '*'; + const DASHBOARDICONS_URL_ROOT = 'https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/'; + const DASHBOARDICONS_URL = self::DASHBOARDICONS_URL_ROOT . '*'; + public static function iconsCollectionProvider() : array { return [ - 'TFA' => [ - 'tfa', - ], - 'SELFH' => [ - 'selfh', - ], - 'DASHBOARDICONS' => [ - 'dashboardicons', - ], + 'TFA' => [[ + 'name' => 'tfa', + 'class' => TfaLogoLib::class, + + ]], + 'SELFH' => [[ + 'name' => 'selfh', + 'class' => SelfhLogoLib::class, + ]], + 'DASHBOARDICONS' => [[ + 'name' => 'dashboardicons', + 'class' => DashboardiconsLogoLib::class, + ]], ]; } diff --git a/tests/Data/HttpRequestTestData.php b/tests/Data/HttpRequestTestData.php index d18b49db..4e96f69d 100644 --- a/tests/Data/HttpRequestTestData.php +++ b/tests/Data/HttpRequestTestData.php @@ -10,6 +10,12 @@ class HttpRequestTestData const SVG_LOGO_BODY = ''; + const SVG_LOGO_BODY_VARIANT_REGULAR = ''; + + const SVG_LOGO_BODY_VARIANT_LIGHT = ''; + + const SVG_LOGO_BODY_VARIANT_DARK = ''; + const TFA_JSON_BODY = ' [ [ diff --git a/tests/Feature/Http/Requests/LoginRequestTest.php b/tests/Feature/Http/Requests/LoginRequestTest.php index f51ad5ee..203afb8d 100644 --- a/tests/Feature/Http/Requests/LoginRequestTest.php +++ b/tests/Feature/Http/Requests/LoginRequestTest.php @@ -35,7 +35,9 @@ class LoginRequestTest extends FeatureTestCase 'email' => 'JOHN.DOE@example.com', ]); - $request = new LoginRequest; + $request = new LoginRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -66,7 +68,9 @@ class LoginRequestTest extends FeatureTestCase 'email' => 'JOHN.DOE@example.com', ]); - $request = new LoginRequest; + $request = new LoginRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Feature/Http/Requests/UserDeleteRequestTest.php b/tests/Feature/Http/Requests/UserDeleteRequestTest.php index d14f07c0..84a6b34f 100644 --- a/tests/Feature/Http/Requests/UserDeleteRequestTest.php +++ b/tests/Feature/Http/Requests/UserDeleteRequestTest.php @@ -35,7 +35,9 @@ class UserDeleteRequestTest extends FeatureTestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new UserDeleteRequest; + $request = new UserDeleteRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -57,7 +59,9 @@ class UserDeleteRequestTest extends FeatureTestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new UserDeleteRequest; + $request = new UserDeleteRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Feature/Http/Requests/UserPatchPwdRequestTest.php b/tests/Feature/Http/Requests/UserPatchPwdRequestTest.php index 3742a013..ae0f6af9 100644 --- a/tests/Feature/Http/Requests/UserPatchPwdRequestTest.php +++ b/tests/Feature/Http/Requests/UserPatchPwdRequestTest.php @@ -35,7 +35,9 @@ class UserPatchPwdRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new UserPatchPwdRequest; + $request = new UserPatchPwdRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -59,7 +61,9 @@ class UserPatchPwdRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new UserPatchPwdRequest; + $request = new UserPatchPwdRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Feature/Http/Requests/UserStoreRequestTest.php b/tests/Feature/Http/Requests/UserStoreRequestTest.php index 399d6d3a..32917ef2 100644 --- a/tests/Feature/Http/Requests/UserStoreRequestTest.php +++ b/tests/Feature/Http/Requests/UserStoreRequestTest.php @@ -36,7 +36,9 @@ class UserStoreRequestTest extends FeatureTestCase 'email' => 'jane@example.com', ]); - $request = new UserStoreRequest; + $request = new UserStoreRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -72,7 +74,9 @@ class UserStoreRequestTest extends FeatureTestCase 'email' => 'john@example.com', ]); - $request = new UserStoreRequest; + $request = new UserStoreRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Feature/Http/Requests/WebauthnAssertedRequestTest.php b/tests/Feature/Http/Requests/WebauthnAssertedRequestTest.php index e000c6ae..d7068fb8 100644 --- a/tests/Feature/Http/Requests/WebauthnAssertedRequestTest.php +++ b/tests/Feature/Http/Requests/WebauthnAssertedRequestTest.php @@ -22,7 +22,9 @@ class WebauthnAssertedRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new WebauthnAssertedRequest; + $request = new WebauthnAssertedRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -53,7 +55,9 @@ class WebauthnAssertedRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new WebauthnAssertedRequest; + $request = new WebauthnAssertedRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Feature/Http/Requests/WebauthnRenameRequestTest.php b/tests/Feature/Http/Requests/WebauthnRenameRequestTest.php index 726fae05..76a929dd 100644 --- a/tests/Feature/Http/Requests/WebauthnRenameRequestTest.php +++ b/tests/Feature/Http/Requests/WebauthnRenameRequestTest.php @@ -35,7 +35,9 @@ class WebauthnRenameRequestTest extends TestCase #[DataProvider('provideValidData')] public function test_valid_data(array $data) : void { - $request = new WebauthnRenameRequest; + $request = new WebauthnRenameRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertFalse($validator->fails()); @@ -57,7 +59,9 @@ class WebauthnRenameRequestTest extends TestCase #[DataProvider('provideInvalidData')] public function test_invalid_data(array $data) : void { - $request = new WebauthnRenameRequest; + $request = new WebauthnRenameRequest; + $request->merge($data); + $validator = Validator::make($data, $request->rules()); $this->assertTrue($validator->fails()); diff --git a/tests/Feature/Services/IconServiceTest.php b/tests/Feature/Services/IconServiceTest.php index 501422b4..6021899f 100644 --- a/tests/Feature/Services/IconServiceTest.php +++ b/tests/Feature/Services/IconServiceTest.php @@ -40,10 +40,10 @@ class IconServiceTest extends FeatureTestCase Http::preventStrayRequests(); Http::fake([ - 'https://raw.githubusercontent.com/2factorauth/twofactorauth/master/img/*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - 'https://cdn.jsdelivr.net/gh/selfhst/icons/*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - 'https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - TfaLogoLib::TFA_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), + CommonDataProvider::TFA_URL => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), + CommonDataProvider::SELFH_URL => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), + CommonDataProvider::DASHBOARDICONS_URL => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), + TfaLogoLib::TFA_JSON_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), ]); Http::fake([ OtpTestData::EXTERNAL_IMAGE_URL_DECODED => Http::response((new FileFactory)->image('file.png', 10, 10)->tempFile, 200), diff --git a/tests/Feature/Services/LogoLib/TfaLogoLibTest.php b/tests/Feature/Services/LogoLib/TfaLogoLibTest.php deleted file mode 100644 index 950f81c0..00000000 --- a/tests/Feature/Services/LogoLib/TfaLogoLibTest.php +++ /dev/null @@ -1,109 +0,0 @@ - Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - TfalogoLib::TFA_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), - ]); - - $this->tfaLogoLib = $this->app->make(TfalogoLib::class); - $icon = $this->tfaLogoLib->getIcon('service'); - - $this->assertNotNull($icon); - Storage::disk('icons')->assertExists($icon); - } - - #[Test] - public function test_getIcon_returns_null_when_github_request_fails() - { - Http::preventStrayRequests(); - Http::fake([ - TfalogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - TfalogoLib::TFA_URL => Http::response('not found', 404), - ]); - - $this->tfaLogoLib = $this->app->make(TfalogoLib::class); - $icon = $this->tfaLogoLib->getIcon('service'); - - $this->assertEquals(null, $icon); - } - - #[Test] - public function test_getIcon_returns_null_when_logo_fetching_fails() - { - Http::preventStrayRequests(); - Http::fake([ - TfalogoLib::IMG_URL . '*' => Http::response('not found', 404), - TfalogoLib::TFA_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), - ]); - - $this->tfaLogoLib = $this->app->make(TfalogoLib::class); - $icon = $this->tfaLogoLib->getIcon('service'); - - $this->assertEquals(null, $icon); - } - - #[Test] - public function test_getIcon_returns_null_when_no_logo_exists() - { - Http::preventStrayRequests(); - Http::fake([ - TfalogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - TfalogoLib::TFA_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), - ]); - - $this->tfaLogoLib = $this->app->make(TfalogoLib::class); - $icon = $this->tfaLogoLib->getIcon('no_logo_should_exists_with_this_name'); - - $this->assertEquals(null, $icon); - } - - #[Test] - public function test_TfalogoLib_loads_empty_collection_when_tfajson_fetching_fails() - { - Http::preventStrayRequests(); - Http::fake([ - TfalogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), - TfalogoLib::TFA_URL => Http::response('not found', 404), - ]); - - $this->tfaLogoLib = $this->app->make(TfalogoLib::class); - $icon = $this->tfaLogoLib->getIcon('service'); - - $this->assertNull($icon); - Storage::disk('logos')->assertMissing(TfalogoLib::TFA_JSON); - } -} diff --git a/tests/Feature/Services/LogoLibsTest.php b/tests/Feature/Services/LogoLibsTest.php new file mode 100644 index 00000000..763ceedd --- /dev/null +++ b/tests/Feature/Services/LogoLibsTest.php @@ -0,0 +1,240 @@ + Http::response($logo['svg'], 200), + ]); + + $this->logoLib = $this->app->make($logo['class']); + $icon = $this->logoLib->getIcon('myservice', $logo['variant']); + + $this->assertNotNull($icon); + Storage::disk('icons')->assertExists($icon); + + // Don't know why but with a faked storage, when an svg file is put to the disk, the svg is prefixed with an xml tag + // so we prepend it manually for the assert to work as expected. + $this->assertEquals(trim(Storage::disk('icons')->get($icon)), ' ' . $logo['svg']); + } + + /** + * Provide Valid data for validation test + */ + public static function provideLogoData() : array + { + return [ + 'SELFH_REGULAR' => [[ + 'variant' => 'regular', + 'url' => CommonDataProvider::SELFH_URL_ROOT . 'svg/myservice.svg', + 'svg' => HttpRequestTestData::SVG_LOGO_BODY_VARIANT_REGULAR, + 'class' => SelfhLogoLib::class, + ]], + 'SELFH_LIGHT' => [[ + 'variant' => 'light', + 'url' => CommonDataProvider::SELFH_URL_ROOT . 'svg/myservice-light.svg', + 'svg' => HttpRequestTestData::SVG_LOGO_BODY_VARIANT_LIGHT, + 'class' => SelfhLogoLib::class, + ]], + 'SELFH_DARK' => [[ + 'variant' => 'dark', + 'url' => CommonDataProvider::SELFH_URL_ROOT . 'svg/myservice-dark.svg', + 'svg' => HttpRequestTestData::SVG_LOGO_BODY_VARIANT_DARK, + 'class' => SelfhLogoLib::class, + ]], + 'DASHBOARDICONS_REGULAR' => [[ + 'variant' => 'regular', + 'url' => CommonDataProvider::DASHBOARDICONS_URL_ROOT . 'svg/myservice.svg', + 'svg' => HttpRequestTestData::SVG_LOGO_BODY_VARIANT_LIGHT, + 'class' => DashboardiconsLogoLib::class, + ]], + 'DASHBOARDICONS_LIGHT' => [[ + 'variant' => 'light', + 'url' => CommonDataProvider::DASHBOARDICONS_URL_ROOT . 'svg/myservice-light.svg', + 'svg' => HttpRequestTestData::SVG_LOGO_BODY_VARIANT_LIGHT, + 'class' => DashboardiconsLogoLib::class, + ]], + 'DASHBOARDICONS_DARK' => [[ + 'variant' => 'dark', + 'url' => CommonDataProvider::DASHBOARDICONS_URL_ROOT . 'svg/myservice-dark.svg', + 'svg' => HttpRequestTestData::SVG_LOGO_BODY_VARIANT_DARK, + 'class' => DashboardiconsLogoLib::class, + ]], + ]; + } + + #[Test] + public function test_getIcon_fetches_png_when_svg_is_not_available() + { + Http::preventStrayRequests(); + Http::fake([ + CommonDataProvider::SELFH_URL_ROOT . 'svg/myservice.svg' => Http::response('not found', 404), + CommonDataProvider::SELFH_URL_ROOT . 'png/myservice.png' => Http::response(base64_decode(OtpTestData::ICON_PNG_DATA), 200), + ]); + + $this->logoLib = $this->app->make(SelfhLogoLib::class); + $icon = $this->logoLib->getIcon('myservice'); + + $this->assertStringEndsWith('.png', $icon); + } + + #[Test] + public function test_getIcon_fallbacks_to_user_preferences_when_variant_is_omitted() + { + $user = User::factory()->create(); + $user['preferences->iconVariant'] = 'dark'; + $user->save(); + + Http::preventStrayRequests(); + Http::fake([ + CommonDataProvider::SELFH_URL_ROOT . 'svg/myservice.svg' => Http::response(HttpRequestTestData::SVG_LOGO_BODY_VARIANT_REGULAR, 200), + CommonDataProvider::SELFH_URL_ROOT . 'svg/myservice-dark.svg' => Http::response(HttpRequestTestData::SVG_LOGO_BODY_VARIANT_DARK, 200), + ]); + + $this->logoLib = $this->app->make(SelfhLogoLib::class); + $icon = $this->actingAs($user)->logoLib->getIcon('myservice'); + + $this->assertEquals(trim(Storage::disk('icons')->get($icon)), ' ' . HttpRequestTestData::SVG_LOGO_BODY_VARIANT_DARK); + } + + #[Test] + #[DataProvider('provideVariantInvalidData')] + public function test_getIcon_fallbacks_to_regular_when_variant_is_invalid_without_auth($variant) + { + Http::preventStrayRequests(); + Http::fake([ + CommonDataProvider::SELFH_URL_ROOT . 'svg/myservice.svg' => Http::response(HttpRequestTestData::SVG_LOGO_BODY_VARIANT_REGULAR, 200), + ]); + + $this->logoLib = $this->app->make(SelfhLogoLib::class); + $icon = $this->logoLib->getIcon('myservice', $variant); + + $this->assertNotNull($icon); + } + + /** + * Provide invalid variant data for validation test + */ + public static function provideVariantInvalidData() : array + { + return [ + 'INVALID_VARIANT' => [ + 'not_a_valid_variant' + ], + 'NULL_VARIANT' => [ + null + ], + 'EMPTY_VARIANT' => [ + '' + ], + ]; + } + + #[Test] + public function test_getIcon_returns_null_when_tfa_github_request_fails() + { + Http::preventStrayRequests(); + Http::fake([ + CommonDataProvider::TFA_URL => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), + TfalogoLib::TFA_JSON_URL => Http::response('not found', 404), + ]); + + $this->logoLib = $this->app->make(TfalogoLib::class); + $icon = $this->logoLib->getIcon('service'); + + $this->assertEquals(null, $icon); + } + + #[Test] + #[DataProviderExternal(CommonDataProvider::class, 'iconsCollectionProvider')] + public function test_getIcon_returns_null_when_logo_fetching_fails(array $iconProvider) + { + Http::preventStrayRequests(); + Http::fake([ + CommonDataProvider::TFA_URL => Http::response('not found', 404), + CommonDataProvider::SELFH_URL => Http::response('not found', 404), + CommonDataProvider::DASHBOARDICONS_URL => Http::response('not found', 404), + TfalogoLib::TFA_JSON_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), + ]); + + $this->logoLib = $this->app->make($iconProvider['class']); + $icon = $this->logoLib->getIcon('service'); + + $this->assertEquals(null, $icon); + } + + #[Test] + public function test_getIcon_returns_null_when_no_logo_exists_in_the_tfa_collection() + { + Http::preventStrayRequests(); + Http::fake([ + CommonDataProvider::TFA_URL => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), + TfalogoLib::TFA_JSON_URL => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200), + ]); + + $this->logoLib = $this->app->make(TfalogoLib::class); + $icon = $this->logoLib->getIcon('no_logo_should_exists_with_this_name'); + + $this->assertEquals(null, $icon); + } + + #[Test] + public function test_TfalogoLib_loads_empty_collection_when_tfajson_fetching_fails() + { + Http::preventStrayRequests(); + Http::fake([ + CommonDataProvider::TFA_URL => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200), + TfalogoLib::TFA_JSON_URL => Http::response('not found', 404), + ]); + + $this->logoLib = $this->app->make(TfalogoLib::class); + $icon = $this->logoLib->getIcon('service'); + + $this->assertNull($icon); + Storage::disk('logos')->assertMissing(TfalogoLib::TFA_JSON); + } +}