Browse Source

Bind SettingService & GroupService to the Service Container

Bubka 3 years ago
parent
commit
e49c358cda

+ 3 - 3
app/Api/v1/Controllers/GroupController.php

@@ -9,6 +9,7 @@ use App\Api\v1\Requests\GroupAssignRequest;
 use App\Api\v1\Resources\GroupResource;
 use App\Api\v1\Resources\TwoFAccountCollection;
 use App\Http\Controllers\Controller;
+use Illuminate\Support\Facades\App;
 
 class GroupController extends Controller
 {
@@ -21,12 +22,11 @@ class GroupController extends Controller
     /**
      * Create a new controller instance.
      *
-     * @param  \App\Services\GroupService $groupService
      * @return void
      */
-    public function __construct(GroupService $groupService)
+    public function __construct()
     {
-        $this->groupService = $groupService;
+        $this->groupService = App::make(GroupService::class);
     }
 
 

+ 14 - 7
app/Models/TwoFAccount.php

@@ -4,6 +4,7 @@ namespace App\Models;
 
 use Exception;
 use App\Services\LogoService;
+use App\Services\SettingService;
 use App\Models\Dto\TotpDto;
 use App\Models\Dto\HotpDto;
 use App\Events\TwoFAccountDeleted;
@@ -12,7 +13,6 @@ use App\Exceptions\InvalidOtpParameterException;
 use App\Exceptions\UnsupportedOtpTypeException;
 use App\Exceptions\UndecipherableException;
 use Illuminate\Validation\ValidationException;
-use Facades\App\Services\SettingService;
 use Spatie\EloquentSortable\Sortable;
 use Spatie\EloquentSortable\SortableTrait;
 use OTPHP\TOTP;
@@ -393,8 +393,10 @@ class TwoFAccount extends Model implements Sortable
 
         if (!$this->icon && $skipIconFetching) {
             $this->icon = $this->getDefaultIcon();
-        } 
-        if (!$this->icon && SettingService::get('getOfficialIcons') && !$skipIconFetching) {
+        }
+
+        $settingService = App::make(SettingService::class);
+        if (!$this->icon && $settingService->get('getOfficialIcons') && !$skipIconFetching) {
             $this->icon = $this->getDefaultIcon();
         } 
 
@@ -447,7 +449,9 @@ class TwoFAccount extends Model implements Sortable
         if ($this->generator->hasParameter('image')) {
             $this->icon = $this->storeImageAsIcon($this->generator->getParameter('image'));
         }
-        if (!$this->icon && SettingService::get('getOfficialIcons') && !$skipIconFetching) {
+
+        $settingService = App::make(SettingService::class);
+        if (!$this->icon && $settingService->get('getOfficialIcons') && !$skipIconFetching) {
             $this->icon = $this->getDefaultIcon();
         }    
 
@@ -594,8 +598,9 @@ class TwoFAccount extends Model implements Sortable
     private function getDefaultIcon()
     {
         $logoService = App::make(LogoService::class);
+        $settingService = App::make(SettingService::class);
 
-        return SettingService::get('getOfficialIcons') ? $logoService->getIcon($this->service) : null;
+        return $settingService->get('getOfficialIcons') ? $logoService->getIcon($this->service) : null;
     }
 
 
@@ -604,8 +609,9 @@ class TwoFAccount extends Model implements Sortable
      */
     private function decryptOrReturn($value)
     {
+        $settingService = App::make(SettingService::class);
         // Decipher when needed
-        if ( SettingService::get('useEncryption') )
+        if ( $settingService->get('useEncryption') )
         {
             try {
                 return Crypt::decryptString($value);
@@ -625,8 +631,9 @@ class TwoFAccount extends Model implements Sortable
      */
     private function encryptOrReturn($value)
     {
+        $settingService = App::make(SettingService::class);
         // should be replaced by laravel 8 attribute encryption casting
-        return SettingService::get('useEncryption') ? Crypt::encryptString($value) : $value;
+        return $settingService->get('useEncryption') ? Crypt::encryptString($value) : $value;
     }
 
 }

+ 12 - 2
app/Providers/TwoFAuthServiceProvider.php

@@ -4,6 +4,8 @@ namespace App\Providers;
 
 use App\Services\LogoService;
 use App\Services\QrCodeService;
+use App\Services\SettingService;
+use App\Services\GroupService;
 use Illuminate\Support\ServiceProvider;
 use Illuminate\Contracts\Support\DeferrableProvider;
 
@@ -16,11 +18,19 @@ class TwoFAuthServiceProvider extends ServiceProvider implements DeferrableProvi
      */
     public function register()
     {
-        $this->app->singleton(LogoService::class, function ($app) {
+        $this->app->singleton(SettingService::class, function () {
+            return new SettingService();
+        });
+
+        $this->app->singleton(GroupService::class, function ($app) {
+            return new GroupService($app->make(SettingService::class));
+        });
+
+        $this->app->singleton(LogoService::class, function () {
             return new LogoService();
         });
 
-        $this->app->singleton(QrCodeService::class, function ($app) {
+        $this->app->singleton(QrCodeService::class, function () {
             return new QrCodeService();
         });
     }

+ 51 - 26
app/Services/SettingService.php

@@ -17,14 +17,19 @@ class SettingService
 {
 
     /**
-     * Determine if the given setting has been customized by the user
-     *
-     * @param  string  $key
-     * @return bool
+     * All user settings
+     * 
+     * @var Collection
      */
-    public function isUserDefined($key) : bool
+    private Collection $settings;
+
+
+    /**
+     * Constructor
+     */
+    public function __construct()
     {
-        return DB::table('options')->where('key', $key)->exists();
+        self::build();
     }
 
 
@@ -36,34 +41,18 @@ class SettingService
      */
     public function get(string $setting)
     {
-        $options = $this->all();
-        $value = $options->get($setting);
-
-        return $value;
+        return $this->settings->get($setting);
     }
 
 
     /**
      * Get all settings
-     *
-     * @return mixed Collection of settings
+     * 
+     * @return Collection the Settings collection
      */
     public function all() : Collection
     {
-        // Get a collection of user saved options
-        $userOptions = DB::table('options')->pluck('value', 'key');
-        $userOptions->transform(function ($item, $key) {
-            return $this->restoreType($item);
-        });
-
-        // Merge 2fauth/app config values as fallback values
-        $settings = collect(config('2fauth.options'))->merge($userOptions);
-        
-        if(!Arr::has($settings, 'lang')) {
-            $settings['lang'] = 'browser';
-        }
-
-        return $settings;
+        return $this->settings;
     }
 
 
@@ -90,6 +79,8 @@ class SettingService
             Option::updateOrCreate(['key' => $setting], ['value' => $value]);
             Log::info(sprintf('Setting %s is now %s', var_export($setting, true), var_export($this->restoreType($value), true)));
         }
+
+        self::build();
     }
 
 
@@ -103,6 +94,40 @@ class SettingService
         Option::where('key', $name)->delete();
         Log::info(sprintf('Setting %s deleted', var_export($name, true)));
     }
+
+    
+    /**
+     * Determine if the given setting has been customized by the user
+     *
+     * @param  string  $key
+     * @return bool
+     */
+    public function isUserDefined($key) : bool
+    {
+        return DB::table('options')->where('key', $key)->exists();
+    }
+
+
+    /**
+     * Set the settings collection
+     */
+    private function build()
+    {
+        // Get a collection of user saved options
+        $userOptions = DB::table('options')->pluck('value', 'key');
+        $userOptions->transform(function ($item, $key) {
+            return $this->restoreType($item);
+        });
+
+        // Merge 2fauth/app config values as fallback values
+        $settings = collect(config('2fauth.options'))->merge($userOptions);
+        
+        if(!Arr::has($settings, 'lang')) {
+            $settings['lang'] = 'browser';
+        }
+
+        $this->settings = $settings;
+    }
     
 
     /**

+ 5 - 5
tests/Feature/Services/GroupServiceTest.php

@@ -5,8 +5,8 @@ namespace Tests\Feature\Services;
 use App\Models\Group;
 use App\Models\TwoFAccount;
 use Tests\FeatureTestCase;
-use Tests\Classes\LocalFile;
-use Illuminate\Support\Facades\DB;
+use App\Services\GroupService;
+use App\Services\SettingService;
 
 
 /**
@@ -15,7 +15,7 @@ use Illuminate\Support\Facades\DB;
 class GroupServiceTest extends FeatureTestCase
 {
     /**
-     * App\Services\QrCodeService $groupService
+     * App\Services\GroupService $groupService
      */
     protected $groupService;
 
@@ -58,8 +58,8 @@ class GroupServiceTest extends FeatureTestCase
     {
         parent::setUp();
 
-        $this->groupService = $this->app->make('App\Services\GroupService');
-        $this->settingService = $this->app->make('App\Services\SettingService');
+        $this->groupService = $this->app->make(GroupService::class);
+        $this->settingService = $this->app->make(SettingService::class);
 
         $this->groupOne = new Group;
         $this->groupOne->name = 'MyGroupOne';

+ 7 - 16
tests/Feature/Services/SettingServiceTest.php

@@ -6,6 +6,7 @@ use Tests\FeatureTestCase;
 use Illuminate\Support\Facades\Crypt;
 use Illuminate\Support\Facades\DB;
 use App\Models\TwoFAccount;
+use App\Services\SettingService;
 
 
 /**
@@ -50,7 +51,7 @@ class SettingServiceTest extends FeatureTestCase
     {
         parent::setUp();
 
-        $this->settingService = $this->app->make('App\Services\SettingService');
+        $this->settingService = $this->app->make(SettingService::class);
 
         $this->twofaccountOne = new TwoFAccount;
         $this->twofaccountOne->legacy_uri = self::TOTP_FULL_CUSTOM_URI;
@@ -85,9 +86,7 @@ class SettingServiceTest extends FeatureTestCase
      */
     public function test_get_string_setting_returns_correct_value()
     {
-        DB::table('options')->insert(
-            [self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_STRING)]
-        );
+        $this->settingService->set(self::SETTING_NAME, self::SETTING_VALUE_STRING);
 
         $this->assertEquals(self::SETTING_VALUE_STRING, $this->settingService->get(self::SETTING_NAME));
     }
@@ -98,9 +97,7 @@ class SettingServiceTest extends FeatureTestCase
      */
     public function test_get_boolean_setting_returns_true()
     {
-        DB::table('options')->insert(
-            [self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_TRUE_TRANSFORMED)]
-        );
+        $this->settingService->set(self::SETTING_NAME, self::SETTING_VALUE_TRUE_TRANSFORMED);
 
         $this->assertEquals(true, $this->settingService->get(self::SETTING_NAME));
     }
@@ -111,9 +108,7 @@ class SettingServiceTest extends FeatureTestCase
      */
     public function test_get_boolean_setting_returns_false()
     {
-        DB::table('options')->insert(
-            [self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_FALSE_TRANSFORMED)]
-        );
+        $this->settingService->set(self::SETTING_NAME, self::SETTING_VALUE_FALSE_TRANSFORMED);
 
         $this->assertEquals(false, $this->settingService->get(self::SETTING_NAME));
     }
@@ -124,9 +119,7 @@ class SettingServiceTest extends FeatureTestCase
      */
     public function test_get_int_setting_returns_int()
     {
-        DB::table('options')->insert(
-            [self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_INT)]
-        );
+        $this->settingService->set(self::SETTING_NAME, self::SETTING_VALUE_INT);
 
         $value = $this->settingService->get(self::SETTING_NAME);
 
@@ -142,9 +135,7 @@ class SettingServiceTest extends FeatureTestCase
     {
         $native_options = config('2fauth.options');
 
-        DB::table('options')->insert(
-            [self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_STRING)]
-        );
+        $this->settingService->set(self::SETTING_NAME, self::SETTING_VALUE_STRING);
 
         $all = $this->settingService->all();
 

+ 13 - 7
tests/Unit/Api/v1/Controllers/GroupControllerTest.php

@@ -6,9 +6,11 @@ use App\Models\Group;
 use Tests\TestCase;
 use App\Models\TwoFAccount;
 use App\Services\GroupService;
+use App\Services\SettingService;
 use Illuminate\Foundation\Testing\WithoutMiddleware;
 use App\Api\v1\Controllers\GroupController;
 use Mockery;
+use Mockery\MockInterface;
 
 /**
  * @covers \App\Api\v1\Controllers\GroupController
@@ -24,7 +26,7 @@ class GroupControllerTest extends TestCase
 
 
     /**
-     * @var \App\Api\v1\Controllers\GroupController mocked controller
+     * @var \App\Api\v1\Controllers\GroupController tested controller
      */
     protected $controller;
 
@@ -39,10 +41,12 @@ class GroupControllerTest extends TestCase
     {
         parent::setUp();
 
-        $this->groupServiceMock = Mockery::mock($this->app->make(GroupService::class));
+        $this->groupServiceMock = $this->mock(GroupService::class);
+
+        // $this->groupServiceMock = Mockery::mock($this->app->make(GroupService::class));
         $this->groupStoreRequest = Mockery::mock('App\Api\v1\Requests\GroupStoreRequest');
 
-        $this->controller = new GroupController($this->groupServiceMock);
+        $this->controller = new GroupController();
     }
 
 
@@ -146,10 +150,12 @@ class GroupControllerTest extends TestCase
     public function test_accounts_returns_api_resources_fetched_using_groupService()
     {
         $group = Group::factory()->make();
-
-        \Facades\App\Services\SettingService::shouldReceive('get')
-            ->with('useEncryption')
-            ->andReturn(false);
+        
+        $this->mock(SettingService::class, function (MockInterface $mock) {
+            $mock->shouldReceive('get')
+                ->with('useEncryption')
+                ->andReturn(false);
+        });
 
         $twofaccounts = TwoFAccount::factory()->count(3)->make();
 

+ 21 - 4
tests/Unit/Events/TwoFAccountDeletedTest.php

@@ -5,7 +5,8 @@ namespace Tests\Unit\Events;
 use App\Models\TwoFAccount;
 use App\Events\TwoFAccountDeleted;
 use Tests\TestCase;
-
+use Mockery\MockInterface;
+use App\Services\SettingService;
 
 /**
  * @covers \App\Events\TwoFAccountDeleted
@@ -17,9 +18,25 @@ class TwoFAccountDeletedTest extends TestCase
      */
     public function test_event_constructor()
     {
-        \Facades\App\Services\SettingService::shouldReceive('get')
-            ->with('useEncryption')
-            ->andReturn(false);
+        $settingService = $this->mock(SettingService::class, function (MockInterface $settingService) {
+            $settingService->shouldReceive('get')
+                ->andReturn(false);
+        });
+
+        // SettingService::shouldReceive('get')
+        //             ->andReturn(false);
+
+        // $settingService->shouldReceive('get')
+        //     ->with('useEncryption')
+        //     ->andReturn(false);
+
+        // $settingService->shouldReceive('get')
+        //     ->with('getOfficialIcons')
+        //     ->andReturn(false);
+
+        // \Facades\App\Services\SettingService::shouldReceive('get')
+        //     ->with('useEncryption')
+        //     ->andReturn(false);
 
         $twofaccount = TwoFAccount::factory()->make();
         $event = new TwoFAccountDeleted($twofaccount);

+ 11 - 3
tests/Unit/Listeners/CleanIconStorageTest.php

@@ -8,6 +8,8 @@ use Tests\TestCase;
 use App\Listeners\CleanIconStorage;
 use Illuminate\Support\Facades\Storage;
 use Illuminate\Support\Facades\Event;
+use Mockery\MockInterface;
+use App\Services\SettingService;
 
 
 /**
@@ -17,9 +19,15 @@ class CleanIconStorageTest extends TestCase
 {
     public function test_it_deletes_icon_file_on_twofaccount_deletion()
     {
-        \Facades\App\Services\SettingService::shouldReceive('get')
-            ->with('useEncryption')
-            ->andReturn(false);
+        $settingService = $this->mock(SettingService::class, function (MockInterface $settingService) {
+            $settingService->shouldReceive('get')
+                ->with('useEncryption')
+                ->andReturn(false);
+        });
+
+        // \Facades\App\Services\SettingService::shouldReceive('get')
+        //     ->with('useEncryption')
+        //     ->andReturn(false);
 
         $twofaccount = TwoFAccount::factory()->make();
         $event = new TwoFAccountDeleted($twofaccount);

+ 29 - 11
tests/Unit/TwoFAccountModelTest.php

@@ -5,9 +5,9 @@ namespace Tests\Unit;
 use App\Models\TwoFAccount;
 use App\Events\TwoFAccountDeleted;
 use Tests\ModelTestCase;
-use Illuminate\Support\Facades\Event;
-use Illuminate\Database\Eloquent\Relations\HasMany;
 use Illuminate\Support\Facades\Crypt;
+use Mockery\MockInterface;
+use App\Services\SettingService;
 
 /**
  * @covers \App\Models\TwoFAccount
@@ -44,9 +44,15 @@ class TwoFAccountModelTest extends ModelTestCase
      */
     public function test_sensitive_attributes_are_stored_encrypted(string $attribute)
     {
-        \Facades\App\Services\SettingService::shouldReceive('get')
-            ->with('useEncryption')
-            ->andReturn(true);
+        $settingService = $this->mock(SettingService::class, function (MockInterface $settingService) {
+            $settingService->shouldReceive('get')
+                ->with('useEncryption')
+                ->andReturn(true);
+        });
+
+        // \Facades\App\Services\SettingService::shouldReceive('get')
+        //     ->with('useEncryption')
+        //     ->andReturn(true);
 
         $twofaccount = TwoFAccount::factory()->make([
             $attribute => 'string',
@@ -80,9 +86,15 @@ class TwoFAccountModelTest extends ModelTestCase
      */
     public function test_sensitive_attributes_are_returned_clear(string $attribute)
     {
-        \Facades\App\Services\SettingService::shouldReceive('get')
-            ->with('useEncryption')
-            ->andReturn(false);
+        $settingService = $this->mock(SettingService::class, function (MockInterface $settingService) {
+            $settingService->shouldReceive('get')
+                ->with('useEncryption')
+                ->andReturn(false);
+        });
+
+        // \Facades\App\Services\SettingService::shouldReceive('get')
+        //     ->with('useEncryption')
+        //     ->andReturn(false);
 
         $twofaccount = TwoFAccount::factory()->make();
 
@@ -97,9 +109,15 @@ class TwoFAccountModelTest extends ModelTestCase
      */
     public function test_indecipherable_attributes_returns_masked_value(string $attribute)
     {
-        \Facades\App\Services\SettingService::shouldReceive('get')
-            ->with('useEncryption')
-            ->andReturn(true);
+        $settingService = $this->mock(SettingService::class, function (MockInterface $settingService) {
+            $settingService->shouldReceive('get')
+                ->with('useEncryption')
+                ->andReturn(true);
+        });
+
+        // \Facades\App\Services\SettingService::shouldReceive('get')
+        //     ->with('useEncryption')
+        //     ->andReturn(true);
 
         Crypt::shouldReceive('encryptString')
             ->andReturn('indecipherableString');