From dc6965c9c9dc374eda8ead9e187b9c9e4bab891d Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 23 Nov 2023 11:11:06 +0100 Subject: [PATCH] Create RedisDecodeCredentialsConfigOption --- CHANGELOG.md | 1 + config/config.php | 2 + .../RedisDecodeCredentialsConfigOption.php | 38 ++++++++++++ .../Option/Redis/RedisServersConfigOption.php | 5 +- ...RedisDecodeCredentialsConfigOptionTest.php | 62 +++++++++++++++++++ .../Redis/RedisServersConfigOptionTest.php | 3 +- 6 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/Config/Option/Redis/RedisDecodeCredentialsConfigOption.php create mode 100644 test/Config/Option/Redis/RedisDecodeCredentialsConfigOptionTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ded4a0f..1abc466 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this * Add `CacheNamespaceConfigOption` to customize the cache namespace. * Add support for PHP 8.3 * [#200](https://github.com/shlinkio/shlink-installer/issues/200) Add Matomo integration config options. +* Add `RedisDecodeCredentialsConfigOption` to enable/disable URL-decoding on redis server credentials. ### Changed * *Nothing* diff --git a/config/config.php b/config/config.php index 103a907..77ad7ed 100644 --- a/config/config.php +++ b/config/config.php @@ -98,6 +98,7 @@ ], 'INTEGRATIONS' => [ 'Redis > servers' => Config\Option\Redis\RedisServersConfigOption::class, + 'Redis > decode credentials' => Config\Option\Redis\RedisDecodeCredentialsConfigOption::class, 'Redis > sentinels service' => Config\Option\Redis\RedisSentinelServiceConfigOption::class, 'Redis > Pub/sub enabled' => Config\Option\Redis\RedisPubSubConfigOption::class, Config\Option\Mercure\EnableMercureConfigOption::class, @@ -140,6 +141,7 @@ Config\Option\UrlShortener\EnableTrailingSlashConfigOption::class => InvokableFactory::class, Config\Option\UrlShortener\ShortUrlModeConfigOption::class => InvokableFactory::class, Config\Option\Redis\RedisServersConfigOption::class => InvokableFactory::class, + Config\Option\Redis\RedisDecodeCredentialsConfigOption::class => InvokableFactory::class, Config\Option\Redis\RedisSentinelServiceConfigOption::class => InvokableFactory::class, Config\Option\Redis\RedisPubSubConfigOption::class => InvokableFactory::class, Config\Option\Visit\VisitsWebhooksConfigOption::class => ConfigAbstractFactory::class, diff --git a/src/Config/Option/Redis/RedisDecodeCredentialsConfigOption.php b/src/Config/Option/Redis/RedisDecodeCredentialsConfigOption.php new file mode 100644 index 0000000..29a799f --- /dev/null +++ b/src/Config/Option/Redis/RedisDecodeCredentialsConfigOption.php @@ -0,0 +1,38 @@ +confirm( + 'Do you want redis credentials to be URL-decoded? ' + . '(If you provided servers with URL-encoded credentials, this should be "yes")', + false, + ); + } + + public function getDependentOption(): string + { + return RedisServersConfigOption::class; + } +} diff --git a/src/Config/Option/Redis/RedisServersConfigOption.php b/src/Config/Option/Redis/RedisServersConfigOption.php index 4ab6c2f..d1b49a7 100644 --- a/src/Config/Option/Redis/RedisServersConfigOption.php +++ b/src/Config/Option/Redis/RedisServersConfigOption.php @@ -27,6 +27,9 @@ public function ask(StyleInterface $io, array $currentOptions): ?string return null; } - return $io->ask('Provide a comma-separated list of URIs (redis servers/sentinel instances)'); + return $io->ask( + 'Provide a comma-separated list of URIs (redis servers/sentinel instances). If they contains credentials ' + . 'with URL-reserved chars, make sure they are URL-encoded', + ); } } diff --git a/test/Config/Option/Redis/RedisDecodeCredentialsConfigOptionTest.php b/test/Config/Option/Redis/RedisDecodeCredentialsConfigOptionTest.php new file mode 100644 index 0000000..35bdf8b --- /dev/null +++ b/test/Config/Option/Redis/RedisDecodeCredentialsConfigOptionTest.php @@ -0,0 +1,62 @@ +configOption = new RedisDecodeCredentialsConfigOption(); + } + + #[Test] + public function returnsExpectedConfig(): void + { + self::assertEquals('REDIS_DECODE_CREDENTIALS', $this->configOption->getEnvVar()); + } + + #[Test] + public function expectedQuestionIsAsked(): void + { + $io = $this->createMock(StyleInterface::class); + $io->expects($this->once())->method('confirm')->with( + 'Do you want redis credentials to be URL-decoded? ' + . '(If you provided servers with URL-encoded credentials, this should be "yes")', + false, + )->willReturn(true); + + $answer = $this->configOption->ask($io, []); + + self::assertEquals(true, $answer); + } + + #[Test, DataProvider('provideCurrentOptions')] + public function shouldBeCalledOnlyIfItDoesNotYetExist(array $currentOptions, bool $expected): void + { + self::assertEquals($expected, $this->configOption->shouldBeAsked($currentOptions)); + } + + public static function provideCurrentOptions(): iterable + { + yield 'not exists in config' => [[], false]; + yield 'exists in config' => [['REDIS_DECODE_CREDENTIALS' => true], false]; + yield 'redis enabled in config' => [[RedisServersConfigOption::ENV_VAR => 'bar'], true]; + } + + #[Test] + public function dependsOnRedisServer(): void + { + self::assertEquals(RedisServersConfigOption::class, $this->configOption->getDependentOption()); + } +} diff --git a/test/Config/Option/Redis/RedisServersConfigOptionTest.php b/test/Config/Option/Redis/RedisServersConfigOptionTest.php index c1a4c27..4b5205a 100644 --- a/test/Config/Option/Redis/RedisServersConfigOptionTest.php +++ b/test/Config/Option/Redis/RedisServersConfigOptionTest.php @@ -52,7 +52,8 @@ public function serversAreRequestedWhenRedisConfigIsProvided(?string $serversAns false, )->willReturn(true); $this->io->expects($this->once())->method('ask')->with( - 'Provide a comma-separated list of URIs (redis servers/sentinel instances)', + 'Provide a comma-separated list of URIs (redis servers/sentinel instances). If they contains credentials ' + . 'with URL-reserved chars, make sure they are URL-encoded', )->willReturn($serversAnswer); $result = $this->configOption->ask($this->io, []);