Skip to content

Commit 5f707b8

Browse files
authored
Merge pull request #6 from redbitcz/plugin-fix
SignUrl: Fix request build from global environment
2 parents ca82325 + 4a9fb5c commit 5f707b8

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

src/Plugin/SignedUrl.php

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public function verifyUrl(string $url, bool $allowRedirect = false): array
174174
// Note: Not parsed by parse_str() to prevent broke URL (repeated arguments like `?same_arg=1&same_arg=2`)
175175
$query = $parsedUrl['query'] ?? '';
176176
if (preg_match(
177-
'/(?<token_key>[?&]' . self::URL_QUERY_TOKEN_KEY . '=)(?<token>[^&]+)(?:$|(?<remaining>&.*$))/D',
177+
'/(?<token_key>(?:^|&|^&)' . self::URL_QUERY_TOKEN_KEY . '=)(?<token>[^&]+)(?:$|(?<remaining>&.*$))/D',
178178
$query,
179179
$matches,
180180
PREG_OFFSET_CAPTURE
@@ -200,7 +200,14 @@ public function verifyUrl(string $url, bool $allowRedirect = false): array
200200
}
201201

202202
$parsedUrl = $this->normalizeUrl($parsedUrl);
203-
$signedUrl = $this->buildUrl(['query' => substr($query, 0, $tokenOffset)] + $parsedUrl);
203+
if ($tokenOffset > 0) {
204+
$parsedUrl['query'] = substr($query, 0, $tokenOffset);
205+
} else {
206+
unset($parsedUrl['query']);
207+
/** @var ParsedUrl $parsedUrl (bypass PhpStan bug) */
208+
}
209+
210+
$signedUrl = $this->buildUrl($parsedUrl);
204211

205212
if ($signedUrl !== $allowedUrl) {
206213
throw new SignedUrlVerificationException('URL doesn\'t match signed URL');
@@ -283,16 +290,24 @@ protected function urlFromGlobal(): string
283290
{
284291
$urlSegments = [];
285292
$urlSegments['scheme'] = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off') ? 'https' : 'http';
286-
$urlSegments['host'] = strtolower($_SERVER['HTTP_HOST'] ?? '');
293+
if (isset($_SERVER['HTTP_HOST'])) {
294+
$urlSegments['host'] = strtolower($_SERVER['HTTP_HOST']);
295+
}
287296

288297
$requestUrl = $_SERVER['REQUEST_URI'] ?? '/';
289298
$requestUrl = preg_replace('#^\w++://[^/]++#', '', $requestUrl);
290299
$tmp = explode('?', $requestUrl, 2);
291300
$urlSegments['path'] = $tmp[0];
292-
$urlSegments['query'] = ($tmp[1] ?? '');
301+
if (isset($tmp[1])) {
302+
$urlSegments['query'] = $tmp[1];
303+
}
293304

294-
$urlSegments['user'] = ($_SERVER['PHP_AUTH_USER'] ?? '');
295-
$urlSegments['pass'] = ($_SERVER['PHP_AUTH_PW'] ?? '');
305+
if (isset($_SERVER['PHP_AUTH_USER'])) {
306+
$urlSegments['user'] = $_SERVER['PHP_AUTH_USER'];
307+
}
308+
if (isset($_SERVER['PHP_AUTH_PW'])) {
309+
$urlSegments['pass'] = $_SERVER['PHP_AUTH_PW'];
310+
}
296311

297312
return $this->buildUrl($urlSegments);
298313
}

tests/Plugin/SignUrlTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,24 @@ public function testVerifyToken(): void
9191
}
9292

9393
public function testVerifyUrl(): void
94+
{
95+
$audience = 'test.' . __FUNCTION__;
96+
$timestamp = 1600000000;
97+
$url = 'https://host.tld/path';
98+
99+
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
100+
$plugin->setTimestamp($timestamp);
101+
$tokenUrl = $plugin->signUrl($url, 1600000600);
102+
103+
$plugin = new SignedUrl(self::KEY_HS256, 'HS256', $audience);
104+
$plugin->setTimestamp($timestamp);
105+
JWT::$timestamp = $timestamp;
106+
$parsed = $plugin->verifyUrl($tokenUrl);
107+
$expected = [['get'], 0, 1, 1600000600];
108+
Assert::equal($expected, $parsed);
109+
}
110+
111+
public function testVerifyUrlQuery(): void
94112
{
95113
$audience = 'test.' . __FUNCTION__;
96114
$timestamp = 1600000000;

0 commit comments

Comments
 (0)