8000 Move UriSigner from HttpKernel to HttpFoundation package · symfony/symfony@93a5575 · GitHub
[go: up one dir, main page]

Skip to content

Commit 93a5575

Browse files
Move UriSigner from HttpKernel to HttpFoundation package
1 parent 2979e1e commit 93a5575

File tree

11 files changed

+164
-9
lines changed

11 files changed

+164
-9
lines changed

src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
use Symfony\Component\HttpFoundation\Request;
1919
use Symfony\Component\HttpFoundation\RequestStack;
2020
use Symfony\Component\HttpFoundation\Response;
21+
use Symfony\Component\HttpFoundation\UriSigner;
2122
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
2223
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
2324
use Symfony\Component\HttpKernel\Fragment\FragmentUriGenerator;
24-
use Symfony\Component\HttpKernel\UriSigner;
2525
use Twig\Environment;
2626
use Twig\Loader\ArrayLoader;
2727
use Twig\RuntimeLoader\RuntimeLoaderInterface;

src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Symfony\Component\HttpFoundation\RequestStack;
3636
use Symfony\Component\HttpFoundation\Response;
3737
use Symfony\Component\HttpFoundation\Session\SessionInterface;
38+
use Symfony\Component\HttpFoundation\UriSigner;
3839
use Symfony\Component\HttpFoundation\UrlHelper;
3940
use Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer;
4041
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate;
@@ -47,7 +48,6 @@
4748
use Symfony\Component\HttpKernel\HttpKernelInterface;
4849
use Symfony\Component\HttpKernel\KernelEvents;
4950
use Symfony\Component\HttpKernel\KernelInterface;
50-
use Symfony\Component\HttpKernel\UriSigner;
5151
use Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner;
5252
use Symfony\Component\Runtime\Runner\Symfony\ResponseRunner;
5353
use Symfony\Component\Runtime\SymfonyRuntime;

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
6.3
55
---
66

7+
* Add `UriSigner` from HttpKernel
78
* Calling `ParameterBag::getDigit()`, `getAlnum()`, `getAlpha()` on an `array` throws a `UnexpectedValueException` instead of a `TypeError`
89
* Add `ParameterBag::getString()` to convert a parameter into string and throw an exception if the value is invalid
910
* Add `ParameterBag::getEnum()`

src/Symfony/Component/HttpKernel/Tests/UriSignerTest.php renamed to src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace Symfony\Component\HttpKernel\Tests;
< 9E7A /code>12+
namespace Symfony\Component\HttpFoundation\Tests;
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\HttpFoundation\Request;
16-
use Symfony\Component\HttpKernel\UriSigner;
16+
use Symfony\Component\HttpFoundation\UriSigner;
1717

1818
class UriSignerTest extends TestCase
1919
{
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpFoundation;
13+
14+
use Symfony\Component\HttpKernel\UriSigner as HttpKernelUriSigner;
15+
16+
/**
17+
* Signs URIs.
18+
*
19+
* @author Fabien Potencier <fabien@symfony.com>
20+
*/
21+
class UriSigner extends HttpKernelUriSigner
22+
{
23+
/**
24+
* @param string $secret A secret
25+
* @param string $parameter Query string parameter to use
26+
*/
27+
public function __construct(#[\SensitiveParameter] string $secret, string $parameter = '_hash')
28+
{
29+
parent::__construct($secret, $parameter, true);
30+
}
31+
}

src/Symfony/Component/HttpKernel/Tests/EventListener/FragmentListenerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\UriSigner;
1617
use Symfony\Component\HttpKernel\Event\RequestEvent;
1718
use Symfony\Component\HttpKernel\EventListener\FragmentListener;
1819
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
1920
use Symfony\Component\HttpKernel\HttpKernelInterface;
20-
use Symfony\Component\HttpKernel\UriSigner;
2121

2222
class FragmentListenerTest extends TestCase
2323
{

src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\UriSigner;
1617
use Symfony\Component\HttpKernel\Controller\ControllerReference;
1718
use Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer;
1819
use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer;
1920
use Symfony\Component\HttpKernel\HttpCache\Esi;
20-
use Symfony\Component\HttpKernel\UriSigner;
2121

2222
class EsiFragmentRendererTest extends TestCase
2323
{

src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\UriSigner;
1617
use Symfony\Component\HttpKernel\Controller\ControllerReference;
1718
use Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer;
18-
use Symfony\Component\HttpKernel\UriSigner;
1919
use Twig\Environment;
2020
use Twig\Loader\ArrayLoader;
2121

src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\UriSigner;
1617
use Symfony\Component\HttpKernel\Controller\ControllerReference;
1718
use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer;
1819
use Symfony\Component\HttpKernel\Fragment\SsiFragmentRenderer;
1920
use Symfony\Component\HttpKernel\HttpCache\Ssi;
20-
use Symfony\Component\HttpKernel\UriSigner;
2121

2222
class SsiFragmentRendererTest extends TestCase
2323
{

src/Symfony/Component/HttpKernel/UriSigner.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@
1212
namespace Symfony\Component\HttpKernel;
1313

1414
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\UriSigner as HttpFoundationUriSigner;
1516

1617
/**
1718
* Signs URIs.
1819
*
1920
* @author Fabien Potencier <fabien@symfony.com>
21+
*
22+
* @deprecated since Symfony 6.3, use {@link HttpFoundationUriSigner} instead
2023
*/
2124
class UriSigner
2225
{
@@ -27,10 +30,14 @@ class UriSigner
2730
* @param string $secret A secret
2831
* @param string $parameter Query string parameter to use
2932
*/
30-
public function __construct(#[\SensitiveParameter] string $secret, string $parameter = '_hash')
33+
public function __construct(#[\SensitiveParameter] string $secret, string $parameter = '_hash', bool $skipDeprecation = false)
3134
{
3235
$this->secret = $secret;
3336
$this->parameter = $parameter;
37+
38+
if ($skipDeprecation) {
39+
trigger_deprecation('symfony/dependency-injection', '6.3', 'The "%s" class is deprecated, use "%s" instead.', self::class, HttpFoundationUriSigner::class);
40+
}
3441
}
3542

3643
/**
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpKernel;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\UriSigner as HttpFoundationUriSigner;
16+
17+
/**
18+
* Signs URIs.
19+
*
20+
* @author Fabien Potencier <fabien@symfony.com>
21+
*
22+
* @deprecated since Symfony 6.3, use {@link HttpFoundationUriSigner} instead
23+
*/
24+
class UriSigner
25+
{
26+
private string $secret;
27+
private string $parameter;
28+
29+
/**
30+
* @param string $secret A secret
31+
* @param string $parameter Query string parameter to use
32+
*/
33+
public function __construct(#[\SensitiveParameter] string $secret, string $parameter = '_hash', bool $skipDeprecation = false)
34+
{
35+
$this->secret = $secret;
36+
$this->parameter = $parameter;
37+
38+
if ($skipDeprecation) {
39+
trigger_deprecation('symfony/dependency-injection', '6.3', 'The "%s" class is deprecated, use "%s" instead.', UriSigner::class, HttpFoundationUriSigner::class);
40+
}
41+
}
42+
43+
/**
44+
* Signs a URI.
45+
*
46+
* The given URI is signed by adding the query string parameter
47+
* which value depends on the URI and the secret.
48+
*/
49+
public function sign(string $uri): string
50+
{
51+
$url = parse_url($uri);
52+
$params = [];
53+
54+
if (isset($url['query'])) {
55+
parse_str($url['query'], $params);
56+
}
57+
58+
$uri = $this->buildUrl($url, $params);
59+
$params[$this->parameter] = $this->computeHash($uri);
60+
61+
return $this->buildUrl($url, $params);
62+
}
63+
64+
/**
65+
* Checks that a URI contains the correct hash.
66+
*/
67+
public function check(string $uri): bool
68+
{
69+
$url = parse_url($uri);
70+
$params = [];
71+
72+
if (isset($url['query'])) {
73+
parse_str($url['query'], $params);
74+
}
75+
76+
if (empty($params[$this->parameter])) {
77+
return false;
78+
}
79+
80+
$hash = $params[$this->parameter];
81+
unset($params[$this->parameter]);
82+
83+
return hash_equals($this->computeHash($this->buildUrl($url, $params)), $hash);
84+
}
85+
86+
public function checkRequest(Request $request): bool
87+
{
88+
$qs = ($qs = $request->server->get('QUERY_STRING')) ? '?'.$qs : '';
89+
90+
// we cannot use $request->getUri() here as we want to work with the original URI (no query string reordering)
91+
return $this->check($request->getSchemeAndHttpHost().$request->getBaseUrl().$request->getPathInfo().$qs);
92+
}
93+
94+
private function computeHash(string $uri): string
95+
{
96+
return base64_encode(hash_hmac('sha256', $uri, $this->secret, true));
97+
}
98+
99+
private function buildUrl(array $url, array $params = []): string
100+
{
101+
ksort($params, \SORT_STRING);
102+
$url['query'] = http_build_query($params, '', '&');
103+
104+
$scheme = isset($url['scheme']) ? $url['scheme'].'://' : '';
105+
$host = $url['host'] ?? '';
106+
$port = isset($url['port']) ? ':'.$url['port'] : '';
107+
$user = $url['user'] ?? '';
108+
$pass = isset($url['pass']) ? ':'.$url['pass'] : '';
109+
$pass = ($user || $pass) ? "$pass@" : '';
110+
$path = $url['path'] ?? '';
111+
$query = $url['query'] ? '?'.$url['query'] : '';
112+
$fragment = isset($url['fragment']) ? '#'.$url['fragment'] : '';
113+
114+
return $scheme.$user.$pass.$host.$port.$path.$query.$fragment;
115+
}
116+
}

0 commit comments

Comments
 (0)
0