You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
1.9 KiB

<?php declare(strict_types=1);
namespace BradyMcD\TAATP\AntiCSRF;
use BradyMcD\TAATP\AntiCSRFInterface;
use BradyMcD\TAATP\SessionInterface;
class Base implements AntiCSRFInterface
{
const CSRF_TOKEN_IDX = "antiCSRF";
const CSRF_EXPIRY_IDX = "antiCSRF_Expiry";
private string $token;
public function __construct(
private SessionInterface $session,
private \Psr\Clock\ClockInterface $clock
)
{
assert($session->live(), "A live session is required to match anti-CSRF tokens across requests.");
$this->generate();
}
/** @SuppressWarnings(PHPMD.Superglobals) */
public function match(): bool
{
$request_token = $_REQUEST[self::CSRF_TOKEN_IDX] ?? false;
if ($request_token && \hash_equals($this->token, $request_token))
{
return !$this->expired();
}
return false;
}
public function expired(): bool
{
return $this->clock->now()->getTimestamp() >= $this->session->get(self::CSRF_EXPIRY_IDX);
}
public function emitStr(): string
{
return
'<input type="hidden" name="'
. self::CSRF_TOKEN_IDX
. '" value="'
. $this->token
. '" />';
}
public function display()
{
echo $this->emitStr();
}
private function expiry(): int
{
return $this->clock->now()->getTimestamp() + 3600;
}
public function generate()
{
$this->session->tryStore(self::CSRF_TOKEN_IDX, \bin2hex(\random_bytes(32)));
$this->token = $this->session->get(self::CSRF_TOKEN_IDX);
$this->session->tryStore(self::CSRF_EXPIRY_IDX, $this->expiry());
}
public function regenerate()
{
$this->session->store(self::CSRF_TOKEN_IDX, \bin2hex(\random_bytes(32)));
$this->token = $this->session->get(self::CSRF_TOKEN_IDX);
$this->session->store(self::CSRF_EXPIRY_IDX, $this->expiry());
}
}
?>