Skip to content

Commit a061e46

Browse files
authored
fix(http): discard unencrypted cookies (#1551)
1 parent a416f94 commit a061e46

File tree

4 files changed

+57
-18
lines changed

4 files changed

+57
-18
lines changed

packages/http/src/Mappers/PsrRequestToGenericRequestMapper.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
use Psr\Http\Message\UploadedFileInterface;
99
use Tempest\Cryptography\Encryption\Encrypter;
1010
use Tempest\Http\Cookie\Cookie;
11+
use Tempest\Http\Cookie\CookieManager;
1112
use Tempest\Http\GenericRequest;
1213
use Tempest\Http\Method;
1314
use Tempest\Http\RequestHeaders;
1415
use Tempest\Http\Upload;
1516
use Tempest\Mapper\Mapper;
1617
use Tempest\Support\Arr;
18+
use Throwable;
1719

1820
use function Tempest\map;
1921
use function Tempest\Support\arr;
@@ -22,6 +24,7 @@
2224
{
2325
public function __construct(
2426
private Encrypter $encrypter,
27+
private CookieManager $cookies,
2528
) {}
2629

2730
public function canMap(mixed $from, mixed $to): bool
@@ -60,13 +63,21 @@ public function map(mixed $from, mixed $to): GenericRequest
6063
'path' => $from->getUri()->getPath(),
6164
'query' => $query,
6265
'files' => $uploads,
63-
'cookies' => Arr\map_iterable(
66+
'cookies' => Arr\filter(Arr\map_iterable(
6467
array: $_COOKIE,
65-
map: fn (string $value, string $key) => new Cookie(
66-
key: $key,
67-
value: $this->encrypter->decrypt($value),
68-
),
69-
),
68+
map: function (string $value, string $key) {
69+
try {
70+
return new Cookie(
71+
key: $key,
72+
value: $this->encrypter->decrypt($value),
73+
);
74+
} catch (Throwable) {
75+
$this->cookies->remove($key);
76+
77+
return null;
78+
}
79+
},
80+
)),
7081
])
7182
->to(GenericRequest::class);
7283
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hello

tests/Integration/Mapper/PsrRequestToRequestMapperTest.php renamed to tests/Integration/Route/PsrRequestToGenericRequestMapperTest.php

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,40 @@
22

33
declare(strict_types=1);
44

5-
namespace Tests\Tempest\Integration\Mapper;
5+
namespace Integration\Route;
66

77
use Laminas\Diactoros\ServerRequest;
88
use Laminas\Diactoros\Stream;
99
use Laminas\Diactoros\UploadedFile;
1010
use Laminas\Diactoros\Uri;
1111
use Tempest\Cryptography\Encryption\Encrypter;
12+
use Tempest\Http\Cookie\CookieManager;
1213
use Tempest\Http\GenericRequest;
1314
use Tempest\Http\Mappers\PsrRequestToGenericRequestMapper;
14-
use Tempest\Http\Method;
1515
use Tempest\Http\Request;
1616
use Tempest\Http\Upload;
1717
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
1818

1919
/**
2020
* @internal
2121
*/
22-
final class PsrRequestToRequestMapperTest extends FrameworkIntegrationTestCase
22+
final class PsrRequestToGenericRequestMapperTest extends FrameworkIntegrationTestCase
2323
{
2424
private Encrypter $encrypter {
2525
get => $this->container->get(Encrypter::class);
2626
}
2727

28+
private CookieManager $cookies {
29+
get => $this->container->get(CookieManager::class);
30+
}
31+
32+
private PsrRequestToGenericRequestMapper $mapper {
33+
get => new PsrRequestToGenericRequestMapper($this->encrypter, $this->cookies);
34+
}
35+
2836
public function test_generic_request_is_used_when_interface_is_passed(): void
2937
{
30-
$mapper = new PsrRequestToGenericRequestMapper($this->encrypter);
31-
32-
$request = $mapper->map(
38+
$request = $this->mapper->map(
3339
from: $this->http->makePsrRequest('/'),
3440
to: Request::class,
3541
);
@@ -45,7 +51,7 @@ public function test_raw(): void
4551

4652
$_COOKIE['test'] = $this->encrypter->encrypt('cookie-value')->serialize();
4753

48-
$request = new PsrRequestToGenericRequestMapper($this->encrypter)->map(new ServerRequest(
54+
$request = $this->mapper->map(new ServerRequest(
4955
uri: new Uri('/json-endpoint'),
5056
method: 'POST',
5157
body: $stream,
@@ -65,10 +71,8 @@ public function test_files(): void
6571

6672
copy(__DIR__ . '/Fixtures/upload.txt', $currentPath);
6773

68-
$mapper = new PsrRequestToGenericRequestMapper($this->encrypter);
69-
7074
/** @var GenericRequest $request */
71-
$request = $mapper->map(
75+
$request = $this->mapper->map(
7276
from: $this->http->makePsrRequest('/', files: [new UploadedFile(
7377
streamOrFile: $currentPath,
7478
size: 1,
@@ -99,7 +103,7 @@ public function test_files(): void
99103

100104
public function test_body_field_in_body(): void
101105
{
102-
$request = new PsrRequestToGenericRequestMapper($this->encrypter)->map(
106+
$request = $this->mapper->map(
103107
from: $this->http->makePsrRequest(
104108
uri: '/',
105109
body: [
@@ -111,4 +115,26 @@ public function test_body_field_in_body(): void
111115

112116
$this->assertSame(['body' => 'text'], $request->body);
113117
}
118+
119+
public function test_unencrypted_cookies_are_discarded(): void
120+
{
121+
$request = $this->mapper->map(
122+
from: $this->http->makePsrRequest(
123+
uri: '/',
124+
body: [
125+
'body' => 'text',
126+
],
127+
cookies: [
128+
'foo' => 'bar',
129+
],
130+
),
131+
to: GenericRequest::class,
132+
);
133+
134+
$this->assertSame([], $request->cookies);
135+
136+
$cookies = $this->cookies->all();
137+
$this->assertSame($cookies['foo']->expiresAt, -1);
138+
$this->assertSame($cookies['foo']->value, '');
139+
}
114140
}

tests/Integration/Route/RequestTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ public function test_request_get(): void
6868

6969
public function test_from_factory(): void
7070
{
71+
$_COOKIE = [];
72+
7173
$_SERVER['REQUEST_METHOD'] = Method::POST->value;
7274
$_SERVER['REQUEST_URI'] = '/test';
7375
$_SERVER['HTTP_X-TEST'] = 'test';
@@ -84,7 +86,6 @@ public function test_from_factory(): void
8486
$this->assertEquals('/test', $request->getUri()->getPath());
8587
$this->assertEquals(['test' => 'test'], $request->getParsedBody());
8688
$this->assertEquals(['x-test' => ['test']], $request->getHeaders());
87-
8889
$this->assertCount(1, $request->getCookieParams());
8990
$this->assertArrayHasKey('test', $request->getCookieParams());
9091
$this->assertSame('test', $this->container->get(Encrypter::class)->decrypt($request->getCookieParams()['test']));

0 commit comments

Comments
 (0)