Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/http/src/Session/VerifyCsrfMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Tempest\Clock\Clock;
use Tempest\Core\AppConfig;
use Tempest\Core\Priority;
use Tempest\Cryptography\Encryption\Encrypter;
use Tempest\Http\Cookie\Cookie;
use Tempest\Http\Cookie\CookieManager;
use Tempest\Http\Method;
Expand All @@ -29,6 +30,7 @@ public function __construct(
private SessionConfig $sessionConfig,
private CookieManager $cookies,
private Clock $clock,
private Encrypter $encrypter,
) {}

public function __invoke(Request $request, HttpMiddlewareCallable $next): Response
Expand Down Expand Up @@ -67,9 +69,14 @@ private function ensureTokenMatches(Request $request): void
{
$tokenFromRequest = $request->get(
key: Session::CSRF_TOKEN_KEY,
default: $request->headers->get(self::CSRF_HEADER_KEY),
);

if (! $tokenFromRequest && $request->headers->has(self::CSRF_HEADER_KEY)) {
$tokenFromRequest = $this->encrypter->decrypt(
urldecode($request->headers->get(self::CSRF_HEADER_KEY)),
);
}

if (! $tokenFromRequest) {
throw new CsrfTokenDidNotMatch();
}
Expand Down
12 changes: 9 additions & 3 deletions tests/Integration/Http/CsrfTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PHPUnit\Framework\Attributes\TestWith;
use Tempest\Core\AppConfig;
use Tempest\Core\Environment;
use Tempest\Cryptography\Encryption\Encrypter;
use Tempest\Http\Cookie\Cookie;
use Tempest\Http\GenericRequest;
use Tempest\Http\Method;
Expand Down Expand Up @@ -84,14 +85,19 @@ public function test_matches_from_body(): void
->assertOk();
}

public function test_matches_from_header(): void
public function test_matches_from_header_when_encrypted(): void
{
$this->container->get(AppConfig::class)->environment = Environment::PRODUCTION;

$session = $this->container->get(Session::class);

// Encrypt the token as it would be in a real request
$sessionCookieValue = $this->container
->get(Encrypter::class)
->encrypt($session->token)
->serialize();

$this->http
->post('/test', headers: [VerifyCsrfMiddleware::CSRF_HEADER_KEY => $session->token])
->post('/test', headers: [VerifyCsrfMiddleware::CSRF_HEADER_KEY => $sessionCookieValue])
->assertOk();
}

Expand Down
Loading