Skip to content

Commit 9e485dd

Browse files
committed
Generate url-safe signatures
1 parent c2508e4 commit 9e485dd

File tree

2 files changed

+17
-10
lines changed

2 files changed

+17
-10
lines changed

Tests/UriSignerTest.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ public function testCheckWithDifferentArgSeparator()
7070
$signer = new UriSigner('foobar');
7171

7272
$this->assertSame(
73-
'http://example.com/foo?_hash=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D&baz=bay&foo=bar',
73+
'http://example.com/foo?_hash=rIOcC_F3DoEGo_vnESjSp7uU9zA9S_-OLhxgMexoPUM&baz=bay&foo=bar',
7474
$signer->sign('http://example.com/foo?foo=bar&baz=bay')
7575
);
7676
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay')));
7777

7878
$this->assertSame(
79-
'http://example.com/foo?_expiration=2145916800&_hash=xLhnPMzV3KqqHaaUffBUJvtRDAZ4%2FZ9Y8Sw%2BgmS%2B82Q%3D&baz=bay&foo=bar',
79+
'http://example.com/foo?_expiration=2145916800&_hash=xLhnPMzV3KqqHaaUffBUJvtRDAZ4_Z9Y8Sw-gmS-82Q&baz=bay&foo=bar',
8080
$signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2038-01-01 00:00:00', new \DateTimeZone('UTC')))
8181
);
8282
$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()
103103
$signer = new UriSigner('foobar', 'qux', 'abc');
104104

105105
$this->assertSame(
106-
'http://example.com/foo?baz=bay&foo=bar&qux=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D',
106+
'http://example.com/foo?baz=bay&foo=bar&qux=rIOcC_F3DoEGo_vnESjSp7uU9zA9S_-OLhxgMexoPUM',
107107
$signer->sign('http://example.com/foo?foo=bar&baz=bay')
108108
);
109109
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay')));
110110

111111
$this->assertSame(
112-
'http://example.com/foo?abc=2145916800&baz=bay&foo=bar&qux=kE4rK2MzeiwrYAKy%2B%2FGKvKA6bnzqCbACBdpC3yGnPVU%3D',
112+
'http://example.com/foo?abc=2145916800&baz=bay&foo=bar&qux=kE4rK2MzeiwrYAKy-_GKvKA6bnzqCbACBdpC3yGnPVU',
113113
$signer->sign('http://example.com/foo?foo=bar&baz=bay', new \DateTimeImmutable('2038-01-01 00:00:00', new \DateTimeZone('UTC')))
114114
);
115115
$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()
120120
$signer = new UriSigner('foobar');
121121

122122
$this->assertSame(
123-
'http://example.com/foo?_hash=EhpAUyEobiM3QTrKxoLOtQq5IsWyWedoXDPqIjzNj5o%3D&bar=foo&foo=bar#foobar',
123+
'http://example.com/foo?_hash=EhpAUyEobiM3QTrKxoLOtQq5IsWyWedoXDPqIjzNj5o&bar=foo&foo=bar#foobar',
124124
$signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar')
125125
);
126126

127127
$this->assertTrue($signer->check($signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar')));
128128

129129
$this->assertSame(
130-
'http://example.com/foo?_expiration=2145916800&_hash=jTdrIE9MJSorNpQmkX6tmOtocxXtHDzIJawcAW4IFYo%3D&bar=foo&foo=bar#foobar',
130+
'http://example.com/foo?_expiration=2145916800&_hash=jTdrIE9MJSorNpQmkX6tmOtocxXtHDzIJawcAW4IFYo&bar=foo&foo=bar#foobar',
131131
$signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar', new \DateTimeImmutable('2038-01-01 00:00:00', new \DateTimeZone('UTC')))
132132
);
133133

@@ -198,4 +198,10 @@ public function testCheckWithUriExpiration()
198198
$this->assertFalse($signer->check($relativeUriFromNow2));
199199
$this->assertFalse($signer->check($relativeUriFromNow3));
200200
}
201+
202+
public function testNonUrlSafeBase64()
203+
{
204+
$signer = new UriSigner('foobar');
205+
$this->assertTrue($signer->check('http://example.com/foo?_hash=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D&baz=bay&foo=bar'));
206+
}
201207
}

UriSigner.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function __construct(
4646
*
4747
* The expiration is added as a query string parameter.
4848
*/
49-
public function sign(string $uri/*, \DateTimeInterface|\DateInterval|int|null $expiration = null*/): string
49+
public function sign(string $uri/* , \DateTimeInterface|\DateInterval|int|null $expiration = null */): string
5050
{
5151
$expiration = null;
5252

@@ -55,7 +55,7 @@ public function sign(string $uri/*, \DateTimeInterface|\DateInterval|int|null $e
5555
}
5656

5757
if (null !== $expiration && !$expiration instanceof \DateTimeInterface && !$expiration instanceof \DateInterval && !\is_int($expiration)) {
58-
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)));
58+
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)));
5959
}
6060

6161
$url = parse_url($uri);
@@ -103,7 +103,8 @@ public function check(string $uri): bool
103103
$hash = $params[$this->hashParameter];
104104
unset($params[$this->hashParameter]);
105105

106-
if (!hash_equals($this->computeHash($this->buildUrl($url, $params)), $hash)) {
106+
// In 8.0, remove support for non-url-safe tokens
107+
if (!hash_equals($this->computeHash($this->buildUrl($url, $params)), strtr(rtrim($hash, '='), ['/' => '_', '+' => '-']))) {
107108
return false;
108109
}
109110

@@ -124,7 +125,7 @@ public function checkRequest(Request $request): bool
124125

125126
private function computeHash(string $uri): string
126127
{
127-
return base64_encode(hash_hmac('sha256', $uri, $this->secret, true));
128+
return strtr(rtrim(base64_encode(hash_hmac('sha256', $uri, $this->secret, true)), '='), ['/' => '_', '+' => '-']);
128129
}
129130

130131
private function buildUrl(array $url, array $params = []): string

0 commit comments

Comments
 (0)