2FAuth/tests/Feature/Services/SettingServiceTest.php

369 lines
12 KiB
PHP
Raw Normal View History

2021-11-22 01:09:54 +01:00
<?php
2021-11-30 17:39:33 +01:00
namespace Tests\Feature\Services;
2021-11-22 01:09:54 +01:00
2022-11-22 15:15:52 +01:00
use App\Facades\Settings;
use App\Models\TwoFAccount;
2023-02-25 21:12:10 +01:00
use App\Services\SettingService;
use Illuminate\Support\Facades\Cache;
2023-02-25 21:12:10 +01:00
use Illuminate\Support\Facades\Crypt;
2021-11-22 01:09:54 +01:00
use Illuminate\Support\Facades\DB;
2023-08-01 11:28:27 +02:00
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
2022-11-22 15:15:52 +01:00
use Tests\FeatureTestCase;
2021-11-30 17:39:33 +01:00
/**
2023-08-01 11:28:27 +02:00
* SettingServiceTest test class
2021-11-30 17:39:33 +01:00
*/
2023-08-01 11:28:27 +02:00
#[CoversClass(SettingService::class)]
#[CoversClass(Settings::class)]
2021-11-30 17:39:33 +01:00
class SettingServiceTest extends FeatureTestCase
2021-11-22 01:09:54 +01:00
{
2021-11-30 17:39:33 +01:00
/**
2021-12-02 13:15:53 +01:00
* App\Models\Group $groupOne, $groupTwo
2021-11-30 17:39:33 +01:00
*/
2022-11-22 15:15:52 +01:00
protected $twofaccountOne;
protected $twofaccountTwo;
2021-11-30 17:39:33 +01:00
2021-11-22 01:09:54 +01:00
private const KEY = 'key';
2022-11-22 15:15:52 +01:00
2021-11-22 01:09:54 +01:00
private const VALUE = 'value';
2022-11-22 15:15:52 +01:00
2021-11-22 01:09:54 +01:00
private const SETTING_NAME = 'MySetting';
2022-11-22 15:15:52 +01:00
2021-11-22 01:09:54 +01:00
private const SETTING_NAME_ALT = 'MySettingAlt';
2022-11-22 15:15:52 +01:00
2021-11-22 01:09:54 +01:00
private const SETTING_VALUE_STRING = 'MyValue';
2022-11-22 15:15:52 +01:00
2021-11-22 01:09:54 +01:00
private const SETTING_VALUE_TRUE_TRANSFORMED = '{{1}}';
2022-11-22 15:15:52 +01:00
2021-11-22 01:09:54 +01:00
private const SETTING_VALUE_FALSE_TRANSFORMED = '{{}}';
2022-11-22 15:15:52 +01:00
2021-11-22 01:09:54 +01:00
private const SETTING_VALUE_INT = 10;
private const SETTING_VALUE_FLOAT = 10.5;
2021-11-30 17:39:33 +01:00
private const ACCOUNT = 'account';
2022-11-22 15:15:52 +01:00
2021-11-30 17:39:33 +01:00
private const SERVICE = 'service';
2022-11-22 15:15:52 +01:00
2021-11-30 17:39:33 +01:00
private const SECRET = 'A4GRFHVVRBGY7UIW';
2022-11-22 15:15:52 +01:00
2021-11-30 17:39:33 +01:00
private const ALGORITHM_CUSTOM = 'sha256';
2022-11-22 15:15:52 +01:00
2021-11-30 17:39:33 +01:00
private const DIGITS_CUSTOM = 7;
2022-11-22 15:15:52 +01:00
2021-11-30 17:39:33 +01:00
private const PERIOD_CUSTOM = 40;
2022-11-22 15:15:52 +01:00
2021-11-30 17:39:33 +01:00
private const IMAGE = 'https%3A%2F%2Fen.opensuse.org%2Fimages%2F4%2F44%2FButton-filled-colour.png';
2022-11-22 15:15:52 +01:00
2021-11-30 17:39:33 +01:00
private const ICON = 'test.png';
2022-11-22 15:15:52 +01:00
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;
2021-11-22 01:09:54 +01:00
2022-12-13 12:07:29 +01:00
public function setUp() : void
2021-11-22 01:09:54 +01:00
{
parent::setUp();
2022-11-22 15:15:52 +01:00
$this->twofaccountOne = new TwoFAccount;
2021-11-30 17:39:33 +01:00
$this->twofaccountOne->legacy_uri = self::TOTP_FULL_CUSTOM_URI;
2022-11-22 15:15:52 +01:00
$this->twofaccountOne->service = self::SERVICE;
$this->twofaccountOne->account = self::ACCOUNT;
$this->twofaccountOne->icon = self::ICON;
$this->twofaccountOne->otp_type = 'totp';
$this->twofaccountOne->secret = self::SECRET;
$this->twofaccountOne->digits = self::DIGITS_CUSTOM;
$this->twofaccountOne->algorithm = self::ALGORITHM_CUSTOM;
$this->twofaccountOne->period = self::PERIOD_CUSTOM;
$this->twofaccountOne->counter = null;
2021-11-30 17:39:33 +01:00
$this->twofaccountOne->save();
2022-11-22 15:15:52 +01:00
$this->twofaccountTwo = new TwoFAccount;
2021-11-30 17:39:33 +01:00
$this->twofaccountTwo->legacy_uri = self::TOTP_FULL_CUSTOM_URI;
2022-11-22 15:15:52 +01:00
$this->twofaccountTwo->service = self::SERVICE;
$this->twofaccountTwo->account = self::ACCOUNT;
$this->twofaccountTwo->icon = self::ICON;
$this->twofaccountTwo->otp_type = 'totp';
$this->twofaccountTwo->secret = self::SECRET;
$this->twofaccountTwo->digits = self::DIGITS_CUSTOM;
$this->twofaccountTwo->algorithm = self::ALGORITHM_CUSTOM;
$this->twofaccountTwo->period = self::PERIOD_CUSTOM;
$this->twofaccountTwo->counter = null;
2021-11-30 17:39:33 +01:00
$this->twofaccountTwo->save();
2021-11-22 01:09:54 +01:00
}
#[Test]
2021-11-22 01:09:54 +01:00
public function test_get_string_setting_returns_correct_value()
{
2022-07-30 17:51:02 +02:00
Settings::set(self::SETTING_NAME, self::SETTING_VALUE_STRING);
2021-11-22 01:09:54 +01:00
2022-07-30 17:51:02 +02:00
$this->assertEquals(self::SETTING_VALUE_STRING, Settings::get(self::SETTING_NAME));
2021-11-22 01:09:54 +01:00
}
#[Test]
2021-11-22 01:09:54 +01:00
public function test_get_boolean_setting_returns_true()
{
2022-07-30 17:51:02 +02:00
Settings::set(self::SETTING_NAME, self::SETTING_VALUE_TRUE_TRANSFORMED);
2021-11-22 01:09:54 +01:00
2022-07-30 17:51:02 +02:00
$this->assertEquals(true, Settings::get(self::SETTING_NAME));
2021-11-22 01:09:54 +01:00
}
#[Test]
2021-11-22 01:09:54 +01:00
public function test_get_boolean_setting_returns_false()
{
2022-07-30 17:51:02 +02:00
Settings::set(self::SETTING_NAME, self::SETTING_VALUE_FALSE_TRANSFORMED);
2021-11-22 01:09:54 +01:00
2022-07-30 17:51:02 +02:00
$this->assertEquals(false, Settings::get(self::SETTING_NAME));
2021-11-22 01:09:54 +01:00
}
#[Test]
2021-11-22 01:09:54 +01:00
public function test_get_int_setting_returns_int()
{
2022-07-30 17:51:02 +02:00
Settings::set(self::SETTING_NAME, self::SETTING_VALUE_INT);
2021-11-22 01:09:54 +01:00
2022-07-30 17:51:02 +02:00
$value = Settings::get(self::SETTING_NAME);
2021-11-22 01:09:54 +01:00
$this->assertEquals(self::SETTING_VALUE_INT, $value);
$this->assertIsInt($value);
}
#[Test]
public function test_get_float_setting_returns_float()
{
Settings::set(self::SETTING_NAME, self::SETTING_VALUE_FLOAT);
$value = Settings::get(self::SETTING_NAME);
$this->assertEquals(self::SETTING_VALUE_FLOAT, $value);
$this->assertIsFloat($value);
}
#[Test]
public function test_all_returns_default_and_overloaded_settings()
2021-11-22 01:09:54 +01:00
{
$default_options = config('2fauth.settings');
2021-11-22 01:09:54 +01:00
2022-07-30 17:51:02 +02:00
Settings::set(self::SETTING_NAME, self::SETTING_VALUE_STRING);
2021-11-22 01:09:54 +01:00
2024-06-26 16:02:49 +02:00
$all = Settings::all()->toArray();
2021-11-22 01:09:54 +01:00
$this->assertArrayHasKey(self::SETTING_NAME, $all);
$this->assertEquals($all[self::SETTING_NAME], self::SETTING_VALUE_STRING);
foreach ($default_options as $key => $val) {
2021-11-22 01:09:54 +01:00
$this->assertArrayHasKey($key, $all);
$this->assertEquals($all[$key], $val);
}
}
#[Test]
public function test_set_setting_persist_correct_value_in_db_and_cache()
2021-11-22 01:09:54 +01:00
{
2023-02-25 21:12:10 +01:00
$value = Settings::set(self::SETTING_NAME, self::SETTING_VALUE_STRING);
$cached = Cache::get(SettingService::CACHE_ITEM_NAME); // returns a Collection
2021-11-22 01:09:54 +01:00
$this->assertDatabaseHas('options', [
2022-11-22 15:15:52 +01:00
self::KEY => self::SETTING_NAME,
self::VALUE => self::SETTING_VALUE_STRING,
2021-11-22 01:09:54 +01:00
]);
$this->assertEquals($cached->get(self::SETTING_NAME), self::SETTING_VALUE_STRING);
2021-11-22 01:09:54 +01:00
}
2021-11-30 17:39:33 +01:00
#[Test]
2021-11-30 17:39:33 +01:00
public function test_set_useEncryption_on_encrypts_all_accounts()
{
2022-07-30 17:51:02 +02:00
Settings::set('useEncryption', true);
2021-11-30 17:39:33 +01:00
$twofaccounts = DB::table('twofaccounts')->get();
$twofaccounts->each(function ($item, $key) {
$this->assertEquals(self::ACCOUNT, Crypt::decryptString($item->account));
$this->assertEquals(self::SECRET, Crypt::decryptString($item->secret));
$this->assertEquals(self::TOTP_FULL_CUSTOM_URI, Crypt::decryptString($item->legacy_uri));
});
}
#[Test]
2021-11-30 17:39:33 +01:00
public function test_set_useEncryption_on_twice_prevents_successive_encryption()
{
2022-07-30 17:51:02 +02:00
Settings::set('useEncryption', true);
Settings::set('useEncryption', true);
2021-11-30 17:39:33 +01:00
$twofaccounts = DB::table('twofaccounts')->get();
$twofaccounts->each(function ($item, $key) {
$this->assertEquals(self::ACCOUNT, Crypt::decryptString($item->account));
$this->assertEquals(self::SECRET, Crypt::decryptString($item->secret));
$this->assertEquals(self::TOTP_FULL_CUSTOM_URI, Crypt::decryptString($item->legacy_uri));
});
}
#[Test]
2021-11-30 17:39:33 +01:00
public function test_set_useEncryption_off_decrypts_all_accounts()
{
2022-07-30 17:51:02 +02:00
Settings::set('useEncryption', true);
Settings::set('useEncryption', false);
2021-11-30 17:39:33 +01:00
$twofaccounts = DB::table('twofaccounts')->get();
$twofaccounts->each(function ($item, $key) {
$this->assertEquals(self::ACCOUNT, $item->account);
$this->assertEquals(self::SECRET, $item->secret);
$this->assertEquals(self::TOTP_FULL_CUSTOM_URI, $item->legacy_uri);
});
}
#[Test]
2023-08-01 11:28:27 +02:00
#[DataProvider('provideUndecipherableData')]
2021-11-30 17:39:33 +01:00
public function test_set_useEncryption_off_returns_exception_when_data_are_undecipherable(array $data)
{
$this->expectException(\App\Exceptions\DbEncryptionException::class);
2022-07-30 17:51:02 +02:00
Settings::set('useEncryption', true);
2021-11-30 17:39:33 +01:00
$affected = DB::table('twofaccounts')
->where('id', $this->twofaccountOne->id)
->update($data);
2022-11-22 15:15:52 +01:00
Settings::set('useEncryption', false);
2021-11-30 17:39:33 +01:00
$twofaccount = TwoFAccount::find($this->twofaccountOne->id);
}
/**
* Provide invalid data for validation test
*/
2023-08-01 11:28:27 +02:00
public static function provideUndecipherableData() : array
2021-11-30 17:39:33 +01:00
{
return [
[[
2022-11-22 15:15:52 +01:00
'account' => 'undecipherableString',
2021-11-30 17:39:33 +01:00
]],
[[
2022-11-22 15:15:52 +01:00
'secret' => 'undecipherableString',
2021-11-30 17:39:33 +01:00
]],
[[
2022-11-22 15:15:52 +01:00
'legacy_uri' => 'undecipherableString',
2021-11-30 17:39:33 +01:00
]],
];
}
2021-11-22 01:09:54 +01:00
#[Test]
2021-11-22 01:09:54 +01:00
public function test_set_array_of_settings_persist_correct_values()
{
2022-07-30 17:51:02 +02:00
$value = Settings::set([
2022-11-22 15:15:52 +01:00
self::SETTING_NAME => self::SETTING_VALUE_STRING,
2021-11-22 01:09:54 +01:00
self::SETTING_NAME_ALT => self::SETTING_VALUE_INT,
]);
$cached = Cache::get(SettingService::CACHE_ITEM_NAME); // returns a Collection
2021-11-22 01:09:54 +01:00
$this->assertDatabaseHas('options', [
2022-11-22 15:15:52 +01:00
self::KEY => self::SETTING_NAME,
self::VALUE => self::SETTING_VALUE_STRING,
2021-11-22 01:09:54 +01:00
]);
$this->assertDatabaseHas('options', [
2022-11-22 15:15:52 +01:00
self::KEY => self::SETTING_NAME_ALT,
self::VALUE => self::SETTING_VALUE_INT,
2021-11-22 01:09:54 +01:00
]);
$this->assertEquals($cached->get(self::SETTING_NAME), self::SETTING_VALUE_STRING);
$this->assertEquals($cached->get(self::SETTING_NAME_ALT), self::SETTING_VALUE_INT);
2021-11-22 01:09:54 +01:00
}
#[Test]
2021-11-22 01:09:54 +01:00
public function test_set_true_setting_persist_transformed_boolean()
{
2022-07-30 17:51:02 +02:00
$value = Settings::set(self::SETTING_NAME, true);
2021-11-22 01:09:54 +01:00
$this->assertDatabaseHas('options', [
2022-11-22 15:15:52 +01:00
self::KEY => self::SETTING_NAME,
self::VALUE => self::SETTING_VALUE_TRUE_TRANSFORMED,
2021-11-22 01:09:54 +01:00
]);
}
#[Test]
2021-11-22 01:09:54 +01:00
public function test_set_false_setting_persist_transformed_boolean()
{
2022-07-30 17:51:02 +02:00
$value = Settings::set(self::SETTING_NAME, false);
2021-11-22 01:09:54 +01:00
$this->assertDatabaseHas('options', [
2022-11-22 15:15:52 +01:00
self::KEY => self::SETTING_NAME,
self::VALUE => self::SETTING_VALUE_FALSE_TRANSFORMED,
2021-11-22 01:09:54 +01:00
]);
}
#[Test]
public function test_del_remove_setting_from_db_and_cache()
2021-11-22 01:09:54 +01:00
{
DB::table('options')->insert(
[self::KEY => self::SETTING_NAME, self::VALUE => strval(self::SETTING_VALUE_STRING)]
);
Settings::delete(self::SETTING_NAME);
$cached = Cache::get(SettingService::CACHE_ITEM_NAME); // returns a Collection
2021-11-22 01:09:54 +01:00
$this->assertDatabaseMissing('options', [
2022-11-22 15:15:52 +01:00
self::KEY => self::SETTING_NAME,
self::VALUE => self::SETTING_VALUE_STRING,
2021-11-22 01:09:54 +01:00
]);
$this->assertFalse($cached->has(self::SETTING_NAME));
2021-11-22 01:09:54 +01:00
}
2022-12-09 10:52:17 +01:00
#[Test]
public function test_isEdited_returns_true()
2022-12-09 10:52:17 +01:00
{
DB::table('options')->insert(
2023-04-14 17:54:35 +02:00
[self::KEY => 'showOtpAsDot', self::VALUE => strval(self::SETTING_VALUE_TRUE_TRANSFORMED)]
2022-12-09 10:52:17 +01:00
);
2023-04-14 17:54:35 +02:00
$this->assertTrue(Settings::isEdited('showOtpAsDot'));
2022-12-09 10:52:17 +01:00
}
#[Test]
public function test_isEdited_returns_false()
2022-12-09 10:52:17 +01:00
{
2023-04-14 17:54:35 +02:00
DB::table('options')->where(self::KEY, 'showOtpAsDot')->delete();
2022-12-09 10:52:17 +01:00
2023-04-14 17:54:35 +02:00
$this->assertFalse(Settings::isEdited('showOtpAsDot'));
2022-12-09 10:52:17 +01:00
}
#[Test]
public function test_cache_is_requested_at_instanciation()
{
Cache::shouldReceive('remember')
2023-12-20 16:55:58 +01:00
->andReturn(collect([]));
$settingService = new SettingService();
Cache::shouldHaveReceived('remember');
}
#[Test]
public function test_cache_is_updated_when_setting_is_set()
{
Cache::shouldReceive('remember', 'put')
2023-12-20 16:55:58 +01:00
->andReturn(collect([]), true);
$settingService = new SettingService();
$settingService->set(self::SETTING_NAME, self::SETTING_VALUE_STRING);
Cache::shouldHaveReceived('put');
}
#[Test]
public function test_cache_is_updated_when_setting_is_deleted()
{
Cache::shouldReceive('remember', 'put')
2023-12-20 16:55:58 +01:00
->andReturn(collect([]), true);
$settingService = new SettingService();
$settingService->delete(self::SETTING_NAME);
Cache::shouldHaveReceived('put');
}
2022-11-22 15:15:52 +01:00
}