Bind SettingService & GroupService to the Service Container

This commit is contained in:
Bubka 2022-07-29 18:34:27 +02:00
parent 14609dec95
commit e49c358cda
10 changed files with 166 additions and 84 deletions

View File

@ -9,6 +9,7 @@
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);
}

View File

@ -4,6 +4,7 @@
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\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 @@ public function fillWithOtpParameters(array $parameters, bool $skipIconFetching
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 @@ public function fillWithURI(string $uri, bool $isSteamTotp = false, bool $skipIc
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 @@ private function storeImageAsIcon(string $url)
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 @@ private function getDefaultIcon()
*/
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 @@ private function decryptOrReturn($value)
*/
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;
}
}

View File

@ -4,6 +4,8 @@
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();
});
}

View File

@ -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 @@ public function isUserDefined($key) : bool
*/
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 @@ public function set($setting, $value = null) : void
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 @@ public function delete(string $name) : void
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;
}
/**

View File

@ -5,8 +5,8 @@
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 @@
class GroupServiceTest extends FeatureTestCase
{
/**
* App\Services\QrCodeService $groupService
* App\Services\GroupService $groupService
*/
protected $groupService;
@ -58,8 +58,8 @@ public function setUp() : void
{
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';

View File

@ -6,6 +6,7 @@
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use App\Models\TwoFAccount;
use App\Services\SettingService;
/**
@ -50,7 +51,7 @@ public function setUp() : void
{
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 @@ public function setUp() : void
*/
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 @@ public function test_get_string_setting_returns_correct_value()
*/
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 @@ public function test_get_boolean_setting_returns_true()
*/
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 @@ public function test_get_boolean_setting_returns_false()
*/
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 @@ public function test_all_returns_native_and_user_settings()
{
$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();

View File

@ -6,9 +6,11 @@
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 @@ public function setUp() : void
{
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 @@ public function test_assignAccounts_returns_api_resource_assigned_using_groupSer
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();

View File

@ -5,7 +5,8 @@
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);

View File

@ -8,6 +8,8 @@
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);

View File

@ -5,9 +5,9 @@
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 @@ public function test_model_configuration()
*/
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 @@ public function provideSensitiveAttributes() : array
*/
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 @@ public function test_sensitive_attributes_are_returned_clear(string $attribute)
*/
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');