diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php index d9079b1c7ef17..be617723886fb 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php @@ -80,7 +80,7 @@ public function testGenerateFragmentUri() ]); $twig->addRuntimeLoader($loader); - $this->assertSame('/_fragment?_hash=XCg0hX8QzSwik8Xuu9aMXhoCeI4oJOob7lUVacyOtyY%3D&_path=template%3Dfoo.html.twig%26_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CController%255CTemplateController%253A%253AtemplateAction', $twig->render('index')); + $this->assertSame('/_fragment?_hash=XCg0hX8QzSwik8Xuu9aMXhoCeI4oJOob7lUVacyOtyY&_path=template%3Dfoo.html.twig%26_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CController%255CTemplateController%253A%253AtemplateAction', $twig->render('index')); } protected function getFragmentHandler($returnOrException): FragmentHandler diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 3af8ccbb7ecce..ca751c3f54ae7 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -32,7 +32,7 @@ "symfony/finder": "^6.4|^7.0", "symfony/form": "^6.4|^7.0", "symfony/html-sanitizer": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-foundation": "^7.3", "symfony/http-kernel": "^6.4|^7.0", "symfony/intl": "^6.4|^7.0", "symfony/mime": "^6.4|^7.0", diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php index 6d8966a171ba2..b530d2cbc3bae 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php @@ -50,6 +50,6 @@ public function testGenerateFragmentUri() $client = self::createClient(['test_case' => 'Fragment', 'root_config' => 'config.yml', 'debug' => true]); $client->request('GET', '/fragment_uri'); - $this->assertSame('/_fragment?_hash=CCRGN2D%2FoAJbeGz%2F%2FdoH3bNSPwLCrmwC1zAYCGIKJ0E%3D&_path=_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CTests%255CFunctional%255CBundle%255CTestBundle%255CController%255CFragmentController%253A%253AindexAction', $client->getResponse()->getContent()); + $this->assertSame('/_fragment?_hash=CCRGN2D_oAJbeGz__doH3bNSPwLCrmwC1zAYCGIKJ0E&_path=_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CTests%255CFunctional%255CBundle%255CTestBundle%255CController%255CFragmentController%253A%253AindexAction', $client->getResponse()->getContent()); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index afaa9b03b6832..ef669713fecc0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -25,7 +25,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.4|^7.0", "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-foundation": "^7.3", "symfony/http-kernel": "^7.2", "symfony/polyfill-mbstring": "~1.0", "symfony/filesystem": "^7.1", diff --git a/src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php b/src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php index 949e34760705a..927e2bda84db8 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php @@ -70,13 +70,13 @@ public function testCheckWithDifferentArgSeparator() $signer = new UriSigner('foobar'); $this->assertSame( - 'http://example.com/foo?_hash=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D&baz=bay&foo=bar', + 'http://example.com/foo?_hash=rIOcC_F3DoEGo_vnESjSp7uU9zA9S_-OLhxgMexoPUM&baz=bay&foo=bar', $signer->sign('http://example.com/foo?foo=bar&baz=bay') ); $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay'))); $this->assertSame( - 'http://example.com/foo?_expiration=2145916800&_hash=xLhnPMzV3KqqHaaUffBUJvtRDAZ4%2FZ9Y8Sw%2BgmS%2B82Q%3D&baz=bay&foo=bar', + 'http://example.com/foo?_expiration=2145916800&_hash=xLhnPMzV3KqqHaaUffBUJvtRDAZ4_Z9Y8Sw-gmS-82Q&baz=bay&foo=bar', $signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2038-01-01 00:00:00', new \DateTimeZone('UTC'))) ); $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2099-01-01 00:00:00')))); @@ -103,13 +103,13 @@ public function testCheckWithDifferentParameter() $signer = new UriSigner('foobar', 'qux', 'abc'); $this->assertSame( - 'http://example.com/foo?baz=bay&foo=bar&qux=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D', + 'http://example.com/foo?baz=bay&foo=bar&qux=rIOcC_F3DoEGo_vnESjSp7uU9zA9S_-OLhxgMexoPUM', $signer->sign('http://example.com/foo?foo=bar&baz=bay') ); $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay'))); $this->assertSame( - 'http://example.com/foo?abc=2145916800&baz=bay&foo=bar&qux=kE4rK2MzeiwrYAKy%2B%2FGKvKA6bnzqCbACBdpC3yGnPVU%3D', + 'http://example.com/foo?abc=2145916800&baz=bay&foo=bar&qux=kE4rK2MzeiwrYAKy-_GKvKA6bnzqCbACBdpC3yGnPVU', $signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2038-01-01 00:00:00', new \DateTimeZone('UTC'))) ); $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2099-01-01 00:00:00')))); @@ -120,14 +120,14 @@ public function testSignerWorksWithFragments() $signer = new UriSigner('foobar'); $this->assertSame( - 'http://example.com/foo?_hash=EhpAUyEobiM3QTrKxoLOtQq5IsWyWedoXDPqIjzNj5o%3D&bar=foo&foo=bar#foobar', + 'http://example.com/foo?_hash=EhpAUyEobiM3QTrKxoLOtQq5IsWyWedoXDPqIjzNj5o&bar=foo&foo=bar#foobar', $signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar') ); $this->assertTrue($signer->check($signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar'))); $this->assertSame( - 'http://example.com/foo?_expiration=2145916800&_hash=jTdrIE9MJSorNpQmkX6tmOtocxXtHDzIJawcAW4IFYo%3D&bar=foo&foo=bar#foobar', + 'http://example.com/foo?_expiration=2145916800&_hash=jTdrIE9MJSorNpQmkX6tmOtocxXtHDzIJawcAW4IFYo&bar=foo&foo=bar#foobar', $signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar', new \DateTimeImmutable('2038-01-01 00:00:00', new \DateTimeZone('UTC'))) ); @@ -198,4 +198,10 @@ public function testCheckWithUriExpiration() $this->assertFalse($signer->check($relativeUriFromNow2)); $this->assertFalse($signer->check($relativeUriFromNow3)); } + + public function testNonUrlSafeBase64() + { + $signer = new UriSigner('foobar'); + $this->assertTrue($signer->check('http://example.com/foo?_hash=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D&baz=bay&foo=bar')); + } } diff --git a/src/Symfony/Component/HttpFoundation/UriSigner.php b/src/Symfony/Component/HttpFoundation/UriSigner.php index dd74434894676..1c9e25a5c0151 100644 --- a/src/Symfony/Component/HttpFoundation/UriSigner.php +++ b/src/Symfony/Component/HttpFoundation/UriSigner.php @@ -46,7 +46,7 @@ public function __construct( * * The expiration is added as a query string parameter. */ - public function sign(string $uri/*, \DateTimeInterface|\DateInterval|int|null $expiration = null*/): string + public function sign(string $uri/* , \DateTimeInterface|\DateInterval|int|null $expiration = null */): string { $expiration = null; @@ -55,7 +55,7 @@ public function sign(string $uri/*, \DateTimeInterface|\DateInterval|int|null $e } if (null !== $expiration && !$expiration instanceof \DateTimeInterface && !$expiration instanceof \DateInterval && !\is_int($expiration)) { - throw new \TypeError(\sprintf('The second argument of %s() must be an instance of %s or %s, an integer or null (%s given).', __METHOD__, \DateTimeInterface::class, \DateInterval::class, get_debug_type($expiration))); + throw new \TypeError(\sprintf('The second argument of "%s()" must be an instance of "%s" or "%s", an integer or null (%s given).', __METHOD__, \DateTimeInterface::class, \DateInterval::class, get_debug_type($expiration))); } $url = parse_url($uri); @@ -103,7 +103,8 @@ public function check(string $uri): bool $hash = $params[$this->hashParameter]; unset($params[$this->hashParameter]); - if (!hash_equals($this->computeHash($this->buildUrl($url, $params)), $hash)) { + // In 8.0, remove support for non-url-safe tokens + if (!hash_equals($this->computeHash($this->buildUrl($url, $params)), strtr(rtrim($hash, '='), ['/' => '_', '+' => '-']))) { return false; } @@ -124,7 +125,7 @@ public function checkRequest(Request $request): bool private function computeHash(string $uri): string { - return base64_encode(hash_hmac('sha256', $uri, $this->secret, true)); + return strtr(rtrim(base64_encode(hash_hmac('sha256', $uri, $this->secret, true)), '='), ['/' => '_', '+' => '-']); } private function buildUrl(array $url, array $params = []): string diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php index fa9885d2753cd..6a08d7eae688b 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php @@ -61,7 +61,7 @@ public function testRenderControllerReference() $altReference = new ControllerReference('alt_controller', [], []); $this->assertEquals( - '', + '', $strategy->render($reference, $request, ['alt' => $altReference])->getContent() ); } @@ -79,7 +79,7 @@ public function testRenderControllerReferenceWithAbsoluteUri() $altReference = new ControllerReference('alt_controller', [], []); $this->assertSame( - '', + '', $strategy->render($reference, $request, ['alt' => $altReference, 'absolute_uri' => true])->getContent() ); } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php index f74887ade36f4..82b80a86ff6b3 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php @@ -32,7 +32,7 @@ public function testRenderWithControllerAndSigner() { $strategy = new HIncludeFragmentRenderer(null, new UriSigner('foo')); - $this->assertEquals('', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent()); + $this->assertEquals('', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent()); } public function testRenderWithUri() diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php index 4af00f9f75137..0d3f1dc2d4b62 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php @@ -52,7 +52,7 @@ public function testRenderControllerReference() $altReference = new ControllerReference('alt_controller', [], []); $this->assertEquals( - '', + '', $strategy->render($reference, $request, ['alt' => $altReference])->getContent() ); } @@ -70,7 +70,7 @@ public function testRenderControllerReferenceWithAbsoluteUri() $altReference = new ControllerReference('alt_controller', [], []); $this->assertSame( - '', + '', $strategy->render($reference, $request, ['alt' => $altReference, 'absolute_uri' => true])->getContent() ); } diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 89421417f58f1..e9cb077587abb 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -20,7 +20,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.4|^7.0", "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-foundation": "^7.3", "symfony/polyfill-ctype": "^1.8", "psr/log": "^1|^2|^3" },