TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Frontend\Page;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
||||
use TYPO3\CMS\Core\Crypto\HashAlgo;
|
||||
use TYPO3\CMS\Core\Crypto\HashService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Logic for cHash calculation
|
||||
*/
|
||||
#[Autoconfigure(public: true)]
|
||||
class CacheHashCalculator
|
||||
{
|
||||
/**
|
||||
* Initialise class properties by using the relevant TYPO3 configuration
|
||||
*/
|
||||
public function __construct(
|
||||
protected CacheHashConfiguration $configuration,
|
||||
protected HashService $hashService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Calculates the cHash based on the provided parameters
|
||||
*
|
||||
* @param array $params Array of cHash key-value pairs
|
||||
* @return string Hash of all the values
|
||||
*/
|
||||
public function calculateCacheHash(array $params): string
|
||||
{
|
||||
if ($params === []) {
|
||||
return '';
|
||||
}
|
||||
unset($params['encryptionKey']);
|
||||
ksort($params);
|
||||
$hashService = GeneralUtility::makeInstance(HashService::class);
|
||||
return !empty($params) ? $hashService->hmac(serialize($params), self::class, HashAlgo::SHA3_256) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cHash based on provided query parameters and added values from internal call
|
||||
*
|
||||
* @param string $queryString Query-parameters: "&xxx=yyy&zzz=uuu
|
||||
* @return string Hash of all the values
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function generateForParameters($queryString)
|
||||
{
|
||||
$cacheHashParams = $this->getRelevantParameters($queryString);
|
||||
return $this->calculateCacheHash($cacheHashParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a parameter of the given $queryString requires cHash calculation
|
||||
*
|
||||
* @param string $queryString
|
||||
* @return bool
|
||||
*/
|
||||
public function doParametersRequireCacheHash($queryString)
|
||||
{
|
||||
if (!$this->configuration->hasData(CacheHashConfiguration::ASPECT_REQUIRED_CACHE_HASH_PRESENCE_PARAMETERS)) {
|
||||
return false;
|
||||
}
|
||||
$parameterNames = array_keys($this->splitQueryStringToArray($queryString));
|
||||
foreach ($parameterNames as $parameterName) {
|
||||
$hasRequiredParameter = $this->configuration->applies(
|
||||
CacheHashConfiguration::ASPECT_REQUIRED_CACHE_HASH_PRESENCE_PARAMETERS,
|
||||
$parameterName
|
||||
);
|
||||
if ($hasRequiredParameter) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the input query-parameters into an array with certain parameters filtered out.
|
||||
* Used to create the cHash value
|
||||
*
|
||||
* @param string $queryString Query-parameters: "&xxx=yyy&zzz=uuu
|
||||
* @return array Array with key/value pairs of query-parameters WITHOUT a certain list of
|
||||
* @throws \RuntimeException
|
||||
* @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::typoLink()
|
||||
* @internal
|
||||
*/
|
||||
public function getRelevantParameters($queryString)
|
||||
{
|
||||
$parameters = $this->splitQueryStringToArray($queryString);
|
||||
$relevantParameters = [];
|
||||
foreach ($parameters as $parameterName => $parameterValue) {
|
||||
if ($this->isAdminPanelParameter($parameterName) || $this->isExcludedParameter($parameterName) || $this->isCoreParameter($parameterName)) {
|
||||
continue;
|
||||
}
|
||||
if ($this->hasCachedParametersWhiteList() && !$this->isInCachedParametersWhiteList($parameterName)) {
|
||||
continue;
|
||||
}
|
||||
if (($parameterValue === null || $parameterValue === '') && $this->isAllowedWithEmptyValue($parameterName)) {
|
||||
continue;
|
||||
}
|
||||
$relevantParameters[$parameterName] = $parameterValue;
|
||||
}
|
||||
if (!empty($relevantParameters)) {
|
||||
if (empty($parameters['id'])) {
|
||||
throw new \RuntimeException('ID parameter needs to be passed for the cHash calculation!', 1467983513);
|
||||
}
|
||||
$relevantParameters['id'] = $parameters['id'];
|
||||
// Finish and sort parameters array by keys:
|
||||
ksort($relevantParameters);
|
||||
}
|
||||
return $relevantParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the query string and converts it to an array.
|
||||
* Unlike parse_str it only creates an array with one level.
|
||||
*
|
||||
* e.g. foo[bar]=baz will be array('foo[bar]' => 'baz')
|
||||
*
|
||||
* @param string $queryString
|
||||
* @return array
|
||||
*/
|
||||
protected function splitQueryStringToArray($queryString)
|
||||
{
|
||||
$parameters = array_filter(explode('&', ltrim($queryString, '?')));
|
||||
$parameterArray = [];
|
||||
foreach ($parameters as $parameter) {
|
||||
// should not remove empty values with trimExplode, otherwise cases like &=value, value is used as parameterName.
|
||||
$parts = GeneralUtility::trimExplode('=', $parameter, false);
|
||||
$parameterName = $parts[0];
|
||||
$parameterValue = $parts[1] ?? '';
|
||||
if (trim($parameterName) === '') {
|
||||
// This parameter cannot appear in $_GET in PHP even if its value is not empty, so it should be ignored!
|
||||
continue;
|
||||
}
|
||||
$parameterArray[rawurldecode($parameterName)] = rawurldecode($parameterValue);
|
||||
}
|
||||
return $parameterArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given parameter is out of a known data-set starting
|
||||
* with ADMCMD.
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAdminPanelParameter($key)
|
||||
{
|
||||
return $key === 'ADMCMD_simUser' || $key === 'ADMCMD_simTime' || $key === 'ADMCMD_prev';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given parameter is a core parameter
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
protected function isCoreParameter($key)
|
||||
{
|
||||
return $key === 'id' || $key === 'type' || $key === 'no_cache' || $key === 'cHash' || $key === 'MP' || $key === 'logintype';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given parameter should be excluded from cHash calculation
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
protected function isExcludedParameter($key)
|
||||
{
|
||||
return $this->configuration->applies(
|
||||
CacheHashConfiguration::ASPECT_EXCLUDED_PARAMETERS,
|
||||
$key
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given parameter is an exclusive parameter for cHash calculation
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
protected function isInCachedParametersWhiteList($key)
|
||||
{
|
||||
return $this->configuration->applies(
|
||||
CacheHashConfiguration::ASPECT_CACHED_PARAMETERS_WHITELIST,
|
||||
$key
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether cachedParametersWhiteList parameters are configured
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasCachedParametersWhiteList()
|
||||
{
|
||||
return $this->configuration->hasData(
|
||||
CacheHashConfiguration::ASPECT_CACHED_PARAMETERS_WHITELIST
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given parameter may be used even with an empty value
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAllowedWithEmptyValue($key)
|
||||
{
|
||||
return $this->configuration->shallExcludeAllEmptyParameters()
|
||||
|| $this->configuration->applies(
|
||||
CacheHashConfiguration::ASPECT_EXCLUDED_PARAMETERS_IF_EMPTY,
|
||||
$key
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user