From 3a8d7150861c0b50723f13176fd4dd8b3cdab9be Mon Sep 17 00:00:00 2001
From: Alejandro Celaya <alejandrocelaya@gmail.com>
Date: Tue, 13 Feb 2024 22:32:28 +0100
Subject: [PATCH 1/2] Remove deprecated symbols

---
 CHANGELOG.md                    |  3 +++
 README.md                       |  6 ++----
 functions/functions.php         | 15 ---------------
 src/Cache/RedisFactory.php      | 31 +++++++++++--------------------
 test/Cache/RedisFactoryTest.php | 12 ++----------
 5 files changed, 18 insertions(+), 49 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 223b65a..ddf1308 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
 
 ### Removed
 * Remove `BackwardsCompatibleMonologProcessorDelegator`.
+* Remove support for redis URIs with just a password in place of the username (like `tcp://password@1.2.3.4`).
+* Remove support for non-URL-encoded credentials in redis URIs.
+* Remove `json_decode` and `json_encode` functions.
 
 ### Fixed
 * *Nothing*
diff --git a/README.md b/README.md
index 68bd29f..610e20c 100644
--- a/README.md
+++ b/README.md
@@ -50,16 +50,15 @@ return [
 
         'redis' => [
             'servers' => [
+                // These should be valid URIs. Make sure credentials are URL-encoded
                 'tcp://1.1.1.1:6379',
                 'tcp://2.2.2.2:6379',
                 'tcp://3.3.3.3:6379',
-                'tcp://user:password@4.4.4.4:6379', // Redis ACL (https://redis.io/docs/management/security/acl/)
+                'tcp://user:pass%40word@4.4.4.4:6379', // Redis ACL (https://redis.io/docs/management/security/acl/)
                 'tcp://:password@5.5.5.5:6379', // Redis security (https://redis.io/docs/management/security/)
-                'tcp://password@6.6.6.6:6379', // Same as above, but it's deprecated, as it's not a standard URI
                 'tls://server_with_encryption:6379',
             ],
             'sentinel_service' => 'the_service', // Optional.
-            'decode_credentials' => true // Optional. Defaults to false
         ],
     ],
 
@@ -72,7 +71,6 @@ You can allow caching to be done on a redis instance, redis cluster or redis sen
 
 * `servers`: A list of redis servers. If one is provided, it will be treated as a single instance, and otherwise, a cluster will be assumed.
 * `sentinel_service`: Lets you enable sentinel mode. When provided, the servers will be treated as sentinel instances.
-* `decode_credentials`: Indicates if server credentials (if present) should be URL decoded before passing to redis connection. Otherwise, they are passed verbatim.
 
 > **Note**
 > The entries in `servers` support credentials in the form of `tcp://password@my-server:6379` or `tcp://username:password@my-server:6379`.
diff --git a/functions/functions.php b/functions/functions.php
index be41688..d61bccc 100644
--- a/functions/functions.php
+++ b/functions/functions.php
@@ -5,25 +5,10 @@
 namespace Shlinkio\Shlink\Common;
 
 use Cake\Chronos\Chronos;
-use JsonSerializable;
 use Shlinkio\Shlink\Common\Util\DateRange;
 
 use function array_pad;
 use function explode;
-use function Shlinkio\Shlink\Json\json_decode as shlink_json_decode;
-use function Shlinkio\Shlink\Json\json_encode as shlink_json_encode;
-
-/** @deprecated Use the same function from shlinkio/shlink-json */
-function json_decode(string $json): array
-{
-    return shlink_json_decode($json);
-}
-
-/** @deprecated Use the same function from shlinkio/shlink-json */
-function json_encode(array|JsonSerializable $payload): string
-{
-    return shlink_json_encode($payload);
-}
 
 function buildDateRange(?Chronos $startDate, ?Chronos $endDate): DateRange
 {
diff --git a/src/Cache/RedisFactory.php b/src/Cache/RedisFactory.php
index d905862..3f9ca15 100644
--- a/src/Cache/RedisFactory.php
+++ b/src/Cache/RedisFactory.php
@@ -35,10 +35,9 @@ public function __invoke(ContainerInterface $container): PredisClient
     private function resolveServers(array $redisConfig): array
     {
         $servers = $redisConfig['servers'] ?? [];
-        $decodeCredentials = $redisConfig['decode_credentials'] ?? false;
 
         $servers = array_map(
-            fn (string $server) => $this->normalizeServer($server, $decodeCredentials),
+            fn (string $server) => $this->normalizeServer($server),
             is_string($servers) ? explode(',', $servers) : $servers,
         );
 
@@ -46,7 +45,7 @@ private function resolveServers(array $redisConfig): array
         return count($servers) === 1 ? $servers[0] : $servers;
     }
 
-    private function normalizeServer(string $server, bool $decodeCredentials): array
+    private function normalizeServer(string $server): array
     {
         $parsedServer = parse_url(trim($server));
         if (! is_array($parsedServer)) {
@@ -62,25 +61,17 @@ private function normalizeServer(string $server, bool $decodeCredentials): array
             $parsedServer['ssl'] = SSL::OPTIONS;
         }
 
-        if (! isset($parsedServer['user']) && ! isset($parsedServer['pass'])) {
-            return $parsedServer;
-        }
+        // Set credentials if set
+        $user = $parsedServer['user'] ?? null;
+        $pass = $parsedServer['pass'] ?? null;
+        unset($parsedServer['user'], $parsedServer['pass']);
 
-        // Deprecated. Apply URL decoding only if explicitly requested, for BC. Next major version will always do it
-        $credentialsCallback = static fn (string $val) => ($decodeCredentials ? urldecode($val) : $val);
-
-        if (isset($parsedServer['user']) && ! isset($parsedServer['pass'])) {
-            // For historical reasons, we support URLs in the form of `tcp://redis_password@redis_host:1234`, but this
-            // is deprecated
-            $parsedServer['password'] = $credentialsCallback($parsedServer['user']);
-        } elseif (isset($parsedServer['user'], $parsedServer['pass'])) {
-            if ($parsedServer['user'] !== '') {
-                $parsedServer['username'] = $credentialsCallback($parsedServer['user']);
-            }
-            $parsedServer['password'] = $credentialsCallback($parsedServer['pass']);
+        if ($user !== null && $user !== '') {
+            $parsedServer['username'] = urldecode($user);
+        }
+        if ($pass !== null) {
+            $parsedServer['password'] = urldecode($pass);
         }
-
-        unset($parsedServer['user'], $parsedServer['pass']);
 
         return $parsedServer;
     }
diff --git a/test/Cache/RedisFactoryTest.php b/test/Cache/RedisFactoryTest.php
index 66daf8e..c72e302 100644
--- a/test/Cache/RedisFactoryTest.php
+++ b/test/Cache/RedisFactoryTest.php
@@ -144,19 +144,11 @@ public static function provideServersWithCredentials(): iterable
         yield 'password only' => [[
             'servers' => ['tcp://:baz@1.1.1.1:6379'],
         ], null, 'baz', null];
-        yield 'password only (deprecated)' => [[
+        yield 'username only' => [[
             'servers' => ['tcp://foo@1.1.1.1:6379'],
-        ], null, 'foo', null];
+        ], 'foo', null, null];
         yield 'URL-encoded' => [[
             'servers' => ['tcp://user%3Aname:pass%40word@1.1.1.1:6379'],
-        ], 'user%3Aname', 'pass%40word', null];
-        yield 'URL-encoded, no request decode' => [[
-            'servers' => ['tcp://user%3Aname:pass%40word@1.1.1.1:6379'],
-            'decode_credentials' => false,
-        ], 'user%3Aname', 'pass%40word', null];
-        yield 'URL-encoded, request decode' => [[
-            'servers' => ['tcp://user%3Aname:pass%40word@1.1.1.1:6379'],
-            'decode_credentials' => true,
         ], 'user:name', 'pass@word', null];
         yield 'tls encryption' => [[
             'servers' => ['tls://1.1.1.1:6379'],

From 58dc6a117d5064d02d4818ed0c411ab5a1f89047 Mon Sep 17 00:00:00 2001
From: Alejandro Celaya <alejandrocelaya@gmail.com>
Date: Tue, 13 Feb 2024 22:35:13 +0100
Subject: [PATCH 2/2] Remove no-longer needed PHPStan supression

---
 src/RabbitMq/AMQPConnectionFactory.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/RabbitMq/AMQPConnectionFactory.php b/src/RabbitMq/AMQPConnectionFactory.php
index dd0881c..d2b553a 100644
--- a/src/RabbitMq/AMQPConnectionFactory.php
+++ b/src/RabbitMq/AMQPConnectionFactory.php
@@ -37,7 +37,7 @@ public function __invoke(ContainerInterface $container): AMQPStreamConnection
                 // We have to pass the config as the ssl_protocol to avoid an internal deprecation warning
                 // When the ssl_protocol is a config instance, it is internally set as config.
                 // See https://github.com/php-amqplib/php-amqplib/blob/b4ade54ebe4685873f6316f9a05fc2c77a9e28f9/PhpAmqpLib/Connection/AMQPStreamConnection.php#L48-L55
-                ssl_protocol: $connectionConfig, // @phpstan-ignore-line
+                ssl_protocol: $connectionConfig,
             );
     }