mirror of
https://github.com/skipperbent/simple-php-router.git
synced 2026-06-13 09:13:17 +03:00
132 lines
3.4 KiB
PHP
132 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace Pecee\Http\Middleware;
|
|
|
|
use Pecee\Http\Middleware\Exceptions\TokenMismatchException;
|
|
use Pecee\Http\Request;
|
|
use Pecee\Http\Security\CookieTokenProvider;
|
|
use Pecee\Http\Security\ITokenProvider;
|
|
|
|
class BaseCsrfVerifier implements IMiddleware
|
|
{
|
|
public const POST_KEY = 'csrf_token';
|
|
public const HEADER_KEY = 'X-CSRF-TOKEN';
|
|
|
|
/**
|
|
* Urls to ignore. You can use * to exclude all sub-urls on a given path.
|
|
* For example: /admin/*
|
|
* @var array|null
|
|
*/
|
|
protected array $except = [];
|
|
|
|
/**
|
|
* Urls to include. Can be used to include urls from a certain path.
|
|
* @var array|null
|
|
*/
|
|
protected array $include = [];
|
|
|
|
/**
|
|
* @var ITokenProvider
|
|
*/
|
|
protected ITokenProvider $tokenProvider;
|
|
|
|
/**
|
|
* BaseCsrfVerifier constructor.
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->tokenProvider = new CookieTokenProvider();
|
|
}
|
|
|
|
protected function isIncluded(Request $request): bool
|
|
{
|
|
if (count($this->include) > 0) {
|
|
foreach ($this->include as $includeUrl) {
|
|
$includeUrl = rtrim($includeUrl, '/');
|
|
if ($includeUrl[strlen($includeUrl) - 1] === '*') {
|
|
$includeUrl = rtrim($includeUrl, '*');
|
|
return $request->getUrl()->contains($includeUrl);
|
|
}
|
|
|
|
return ($includeUrl === rtrim($request->getUrl()->getRelativeUrl(false), '/'));
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if the url matches the urls in the except property
|
|
* @param Request $request
|
|
* @return bool
|
|
*/
|
|
protected function skip(Request $request): bool
|
|
{
|
|
if (count($this->except) === 0) {
|
|
return false;
|
|
}
|
|
|
|
foreach ($this->except as $url) {
|
|
$url = rtrim($url, '/');
|
|
if ($url[strlen($url) - 1] === '*') {
|
|
$url = rtrim($url, '*');
|
|
$skip = $request->getUrl()->contains($url);
|
|
} else {
|
|
$skip = ($url === rtrim($request->getUrl()->getRelativeUrl(false), '/'));
|
|
}
|
|
|
|
if ($skip === true) {
|
|
|
|
$skip = !$this->isIncluded($request);
|
|
|
|
if ($skip === false) {
|
|
continue;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Handle request
|
|
*
|
|
* @param Request $request
|
|
* @throws TokenMismatchException
|
|
*/
|
|
public function handle(Request $request): void
|
|
{
|
|
if ($this->skip($request) === false && ($request->isPostBack() === true || $request->isPostBack() === true && $this->isIncluded($request) === true)) {
|
|
|
|
$token = $request->getInputHandler()->value(
|
|
static::POST_KEY,
|
|
$request->getHeader(static::HEADER_KEY),
|
|
);
|
|
|
|
if ($this->tokenProvider->validate((string)$token) === false) {
|
|
throw new TokenMismatchException('Invalid CSRF-token.');
|
|
}
|
|
|
|
}
|
|
|
|
// Refresh existing token
|
|
$this->tokenProvider->refresh();
|
|
}
|
|
|
|
public function getTokenProvider(): ITokenProvider
|
|
{
|
|
return $this->tokenProvider;
|
|
}
|
|
|
|
/**
|
|
* Set token provider
|
|
* @param ITokenProvider $provider
|
|
*/
|
|
public function setTokenProvider(ITokenProvider $provider): void
|
|
{
|
|
$this->tokenProvider = $provider;
|
|
}
|
|
|
|
} |