TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractConverter implements ConverterInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sessionToken;
|
||||
|
||||
/**
|
||||
* @var ConverterDto
|
||||
*/
|
||||
protected $converterDto;
|
||||
|
||||
public function __construct(ConverterDto $converterDto, string $sessionToken = '')
|
||||
{
|
||||
$this->converterDto = $converterDto;
|
||||
$this->sessionToken = $sessionToken;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Form\Domain\Configuration\ArrayProcessing\ArrayProcessing;
|
||||
use TYPO3\CMS\Form\Domain\Configuration\ArrayProcessing\ArrayProcessor;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class AddHmacDataConverter extends AbstractConverter
|
||||
{
|
||||
/**
|
||||
* Add a new value "_orig_<propertyName>" as a sibling of the property key.
|
||||
* "_orig_<propertyName>" is an array which contains the property value
|
||||
* and a hmac hash for the property value.
|
||||
* "_orig_<propertyName>" will be used to validate the form definition on saving.
|
||||
* @see \TYPO3\CMS\Form\Domain\Configuration\FormDefinitionValidationService::validateFormDefinitionProperties()
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value): void
|
||||
{
|
||||
$formDefinition = $this->converterDto->getFormDefinition();
|
||||
|
||||
$renderablePathParts = explode('.', $key);
|
||||
array_pop($renderablePathParts);
|
||||
|
||||
if (count($renderablePathParts) > 1) {
|
||||
$renderablePath = implode('.', $renderablePathParts);
|
||||
$currentFormElement = ArrayUtility::getValueByPath($formDefinition, $renderablePath, '.');
|
||||
} else {
|
||||
$currentFormElement = $formDefinition;
|
||||
}
|
||||
|
||||
$propertyCollectionElements = $currentFormElement['finishers'] ?? $currentFormElement['validators'] ?? [];
|
||||
$propertyCollectionName = $currentFormElement['type'] === 'Form' ? 'finishers' : 'validators';
|
||||
unset($currentFormElement['renderables'], $currentFormElement['finishers'], $currentFormElement['validators']);
|
||||
|
||||
$this->converterDto
|
||||
->setRenderablePathParts($renderablePathParts)
|
||||
->setFormElementIdentifier($value);
|
||||
|
||||
GeneralUtility::makeInstance(ArrayProcessor::class, $currentFormElement)->forEach(
|
||||
GeneralUtility::makeInstance(
|
||||
ArrayProcessing::class,
|
||||
'addHmacData',
|
||||
'^.*',
|
||||
GeneralUtility::makeInstance(
|
||||
AddHmacDataToFormElementPropertyConverter::class,
|
||||
$this->converterDto,
|
||||
$this->sessionToken
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->converterDto->setPropertyCollectionName($propertyCollectionName);
|
||||
foreach ($propertyCollectionElements as $propertyCollectionIndex => $propertyCollectionElement) {
|
||||
$this->converterDto
|
||||
->setPropertyCollectionIndex((int)$propertyCollectionIndex)
|
||||
->setPropertyCollectionElementIdentifier($propertyCollectionElement['identifier']);
|
||||
|
||||
GeneralUtility::makeInstance(ArrayProcessor::class, $propertyCollectionElement)->forEach(
|
||||
GeneralUtility::makeInstance(
|
||||
ArrayProcessing::class,
|
||||
'addHmacData',
|
||||
'^(?!(.*\._label|.*\._value)$).*',
|
||||
GeneralUtility::makeInstance(
|
||||
AddHmacDataToPropertyCollectionElementConverter::class,
|
||||
$this->converterDto,
|
||||
$this->sessionToken
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
use TYPO3\CMS\Core\Crypto\HashService;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class AddHmacDataToFormElementPropertyConverter extends AbstractConverter
|
||||
{
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value): void
|
||||
{
|
||||
$formDefinition = $this->converterDto->getFormDefinition();
|
||||
|
||||
$propertyPathParts = explode('.', $key);
|
||||
$lastKeySegment = array_pop($propertyPathParts);
|
||||
$propertyPathParts[] = '_orig_' . $lastKeySegment;
|
||||
|
||||
$hashService = GeneralUtility::makeInstance(HashService::class);
|
||||
$hmacValuePath = implode('.', array_merge($this->converterDto->getRenderablePathParts(), $propertyPathParts));
|
||||
$hmacValue = [
|
||||
'value' => $value,
|
||||
'hmac' => $hashService->hmac(serialize([$this->converterDto->getFormElementIdentifier(), $key, $value]), $this->sessionToken),
|
||||
];
|
||||
|
||||
$formDefinition = ArrayUtility::setValueByPath($formDefinition, $hmacValuePath, $hmacValue, '.');
|
||||
|
||||
$this->converterDto->setFormDefinition($formDefinition);
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
use TYPO3\CMS\Core\Crypto\HashService;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class AddHmacDataToPropertyCollectionElementConverter extends AbstractConverter
|
||||
{
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value): void
|
||||
{
|
||||
$formDefinition = $this->converterDto->getFormDefinition();
|
||||
|
||||
$propertyPathParts = explode('.', $key);
|
||||
$lastKeySegment = array_pop($propertyPathParts);
|
||||
$propertyPathParts[] = '_orig_' . $lastKeySegment;
|
||||
|
||||
$hmacValuePath = implode('.', array_merge(
|
||||
$this->converterDto->getRenderablePathParts(),
|
||||
[$this->converterDto->getPropertyCollectionName(), $this->converterDto->getPropertyCollectionIndex()],
|
||||
$propertyPathParts
|
||||
));
|
||||
|
||||
$hashService = GeneralUtility::makeInstance(HashService::class);
|
||||
$hmacValue = [
|
||||
'value' => $value,
|
||||
'hmac' => $hashService->hmac(
|
||||
serialize([
|
||||
$this->converterDto->getFormElementIdentifier(),
|
||||
$this->converterDto->getPropertyCollectionName(),
|
||||
$this->converterDto->getPropertyCollectionElementIdentifier(),
|
||||
$key,
|
||||
$value,
|
||||
]),
|
||||
$this->sessionToken
|
||||
),
|
||||
];
|
||||
|
||||
$formDefinition = ArrayUtility::setValueByPath($formDefinition, $hmacValuePath, $hmacValue, '.');
|
||||
|
||||
$this->converterDto->setFormDefinition($formDefinition);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class ConverterDto
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $formDefinition = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $renderablePathParts = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $formElementIdentifier = '';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $propertyCollectionIndex = 0;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $propertyCollectionName = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $propertyCollectionElementIdentifier = '';
|
||||
|
||||
public function __construct(array $formDefinition)
|
||||
{
|
||||
$this->formDefinition = $formDefinition;
|
||||
}
|
||||
|
||||
public function getFormDefinition(): array
|
||||
{
|
||||
return $this->formDefinition;
|
||||
}
|
||||
|
||||
public function setFormDefinition(array $formDefinition): ConverterDto
|
||||
{
|
||||
$this->formDefinition = $formDefinition;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRenderablePathParts(): array
|
||||
{
|
||||
return $this->renderablePathParts;
|
||||
}
|
||||
|
||||
public function setRenderablePathParts(array $renderablePathParts): ConverterDto
|
||||
{
|
||||
$this->renderablePathParts = $renderablePathParts;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFormElementIdentifier(): string
|
||||
{
|
||||
return $this->formElementIdentifier;
|
||||
}
|
||||
|
||||
public function setFormElementIdentifier(string $formElementIdentifier): ConverterDto
|
||||
{
|
||||
$this->formElementIdentifier = $formElementIdentifier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPropertyCollectionIndex(): int
|
||||
{
|
||||
return $this->propertyCollectionIndex;
|
||||
}
|
||||
|
||||
public function setPropertyCollectionIndex(int $propertyCollectionIndex): ConverterDto
|
||||
{
|
||||
$this->propertyCollectionIndex = $propertyCollectionIndex;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPropertyCollectionName(): string
|
||||
{
|
||||
return $this->propertyCollectionName;
|
||||
}
|
||||
|
||||
public function setPropertyCollectionName(string $propertyCollectionName): ConverterDto
|
||||
{
|
||||
$this->propertyCollectionName = $propertyCollectionName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPropertyCollectionElementIdentifier(): string
|
||||
{
|
||||
return $this->propertyCollectionElementIdentifier;
|
||||
}
|
||||
|
||||
public function setPropertyCollectionElementIdentifier(string $propertyCollectionElementIdentifier): ConverterDto
|
||||
{
|
||||
$this->propertyCollectionElementIdentifier = $propertyCollectionElementIdentifier;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface ConverterInterface
|
||||
{
|
||||
public function __construct(ConverterDto $converterDto, string $sessionToken = '');
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value);
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException;
|
||||
|
||||
/**
|
||||
* Apply FlexForm finisher option overrides
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class FinisherOptionsFlexFormOverridesConverter
|
||||
{
|
||||
/**
|
||||
* @var FlexFormFinisherOverridesConverterDto
|
||||
*/
|
||||
protected $converterDto;
|
||||
|
||||
public function __construct(FlexFormFinisherOverridesConverterDto $converterDto)
|
||||
{
|
||||
$this->converterDto = $converterDto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for overriding finisher options with flexform settings
|
||||
* Flexform settings "win": When a setting is set in the form
|
||||
* definition and in flexform the one in flexform will overwrite the
|
||||
* one defined in the form definition.
|
||||
*
|
||||
* Here we adjust the parsed configuration and apply the overrides.
|
||||
*
|
||||
* @param string $_ unused in this context
|
||||
* @param mixed $__ unused in this context
|
||||
* @param array $matches the expression matches from the ArrayProcessor - for example matches of ^(.*)\.config\.type$
|
||||
*/
|
||||
public function __invoke(string $_, $__, array $matches): void
|
||||
{
|
||||
[, $optionKey] = $matches;
|
||||
$prototypeFinisherDefinition = $this->converterDto->getPrototypeFinisherDefinition();
|
||||
$finisherDefinition = $this->converterDto->getFinisherDefinition();
|
||||
$finisherIdentifier = $this->converterDto->getFinisherIdentifier();
|
||||
$flexFormSheetSettings = $this->converterDto->getFlexFormSheetSettings();
|
||||
|
||||
try {
|
||||
$value = ArrayUtility::getValueByPath(
|
||||
$flexFormSheetSettings['finishers'][$finisherIdentifier],
|
||||
$optionKey,
|
||||
'.'
|
||||
);
|
||||
} catch (MissingArrayPathException $exception) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fieldConfiguration = $prototypeFinisherDefinition['FormEngine']['elements'][$optionKey] ?? [];
|
||||
|
||||
if ($fieldConfiguration['section'] ?? false) {
|
||||
if (!is_array($value) || $value === []) {
|
||||
// Do not process empty values for sections
|
||||
return;
|
||||
}
|
||||
|
||||
$processedOptionValue = [];
|
||||
|
||||
foreach ($value as $optionListValue) {
|
||||
$key = $optionListValue[$fieldConfiguration['sectionItemKey']];
|
||||
$value = $optionListValue[$fieldConfiguration['sectionItemValue']];
|
||||
$processedOptionValue[$key] = $value;
|
||||
}
|
||||
|
||||
$value = $processedOptionValue;
|
||||
}
|
||||
|
||||
$optionPath = 'options.' . $optionKey;
|
||||
|
||||
// Skip additional translation for finisher options that were changed via flexform
|
||||
if ($this->optionValueHasChanged($finisherDefinition, $optionPath, $value)) {
|
||||
$finisherDefinition['options']['translation']['propertiesExcludedFromTranslation'][] = $optionKey;
|
||||
}
|
||||
|
||||
$finisherDefinition = ArrayUtility::setValueByPath($finisherDefinition, $optionPath, $value, '.');
|
||||
|
||||
$this->converterDto->setFinisherDefinition($finisherDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if finisher option value differs from finisher definition.
|
||||
*
|
||||
* Compares the given finisher option value with the corresponding value in the
|
||||
* finisher definition. Returns `true` if both values are equal, `false` otherwise.
|
||||
*
|
||||
* @param array<string, mixed> $finisherDefinition
|
||||
*/
|
||||
protected function optionValueHasChanged(array $finisherDefinition, string $optionPath, mixed $value): bool
|
||||
{
|
||||
try {
|
||||
return $value !== ArrayUtility::getValueByPath($finisherDefinition, $optionPath, '.');
|
||||
} catch (MissingArrayPathException) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class FinisherTranslationLanguageConverter extends AbstractConverter
|
||||
{
|
||||
/**
|
||||
* If "finishers.x.options.translation.language" is empty then set the value to "default" and remove
|
||||
* the hmac.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value): void
|
||||
{
|
||||
if (!empty($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$formDefinition = $this->converterDto->getFormDefinition();
|
||||
|
||||
$formDefinition = ArrayUtility::setValueByPath($formDefinition, $key, 'default', '.');
|
||||
|
||||
$hmacPropertyPathParts = explode('.', $key);
|
||||
$lastKeySegment = array_pop($hmacPropertyPathParts);
|
||||
$hmacPropertyPathParts[] = '_orig_' . $lastKeySegment;
|
||||
$hmacValuePath = implode('.', $hmacPropertyPathParts);
|
||||
|
||||
if (ArrayUtility::isValidPath($formDefinition, $hmacValuePath, '.')) {
|
||||
$formDefinition = ArrayUtility::removeByPath($formDefinition, $hmacValuePath, '.');
|
||||
}
|
||||
|
||||
$this->converterDto->setFormDefinition($formDefinition);
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class FlexFormFinisherOverridesConverterDto
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $prototypeFinisherDefinition = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $finisherDefinition = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $finisherIdentifier = '';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $flexFormSheetSettings = [];
|
||||
|
||||
public function __construct(
|
||||
array $prototypeFinisherDefinition,
|
||||
array $finisherDefinition,
|
||||
string $finisherIdentifier,
|
||||
array $flexFormSheetSettings
|
||||
) {
|
||||
$this->prototypeFinisherDefinition = $prototypeFinisherDefinition;
|
||||
$this->finisherDefinition = $finisherDefinition;
|
||||
$this->finisherIdentifier = $finisherIdentifier;
|
||||
$this->flexFormSheetSettings = $flexFormSheetSettings;
|
||||
}
|
||||
|
||||
public function getPrototypeFinisherDefinition(): array
|
||||
{
|
||||
return $this->prototypeFinisherDefinition;
|
||||
}
|
||||
|
||||
public function getFinisherDefinition(): array
|
||||
{
|
||||
return $this->finisherDefinition;
|
||||
}
|
||||
|
||||
public function setFinisherDefinition(array $finisherDefinition): FlexFormFinisherOverridesConverterDto
|
||||
{
|
||||
$this->finisherDefinition = $finisherDefinition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFinisherIdentifier(): string
|
||||
{
|
||||
return $this->finisherIdentifier;
|
||||
}
|
||||
|
||||
public function getFlexFormSheetSettings(): array
|
||||
{
|
||||
return $this->flexFormSheetSettings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Converters;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class RemoveHmacDataConverter extends AbstractConverter
|
||||
{
|
||||
/**
|
||||
* Remove the hmac data ("_orig_<propertyName>") for the corresponding property.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value): void
|
||||
{
|
||||
$formDefinition = $this->converterDto->getFormDefinition();
|
||||
|
||||
$propertyPathParts = explode('.', $key);
|
||||
array_pop($propertyPathParts);
|
||||
$propertyPath = implode('.', $propertyPathParts);
|
||||
$formDefinition = ArrayUtility::removeByPath($formDefinition, $propertyPath, '.');
|
||||
|
||||
$this->converterDto->setFormDefinition($formDefinition);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Validators;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
|
||||
use TYPO3\CMS\Form\Domain\Configuration\FormDefinitionValidationService;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractValidator implements ValidatorInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $currentElement;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sessionToken;
|
||||
|
||||
/**
|
||||
* @var ValidationDto
|
||||
*/
|
||||
protected $validationDto;
|
||||
|
||||
public function __construct(array $currentElement, string $sessionToken, ValidationDto $validationDto)
|
||||
{
|
||||
$this->currentElement = $currentElement;
|
||||
$this->sessionToken = $sessionToken;
|
||||
$this->validationDto = $validationDto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the path in which the hmac value is expected based on the property path.
|
||||
*/
|
||||
protected function buildHmacDataPath(string $propertyPath): string
|
||||
{
|
||||
$pathParts = explode('.', $propertyPath);
|
||||
$lastPathSegment = array_pop($pathParts);
|
||||
$pathParts[] = '_orig_' . $lastPathSegment;
|
||||
|
||||
return implode('.', $pathParts);
|
||||
}
|
||||
|
||||
protected function getFormDefinitionValidationService(): FormDefinitionValidationService
|
||||
{
|
||||
return GeneralUtility::makeInstance(FormDefinitionValidationService::class);
|
||||
}
|
||||
|
||||
protected function getConfigurationService(): ConfigurationService
|
||||
{
|
||||
return GeneralUtility::makeInstance(ConfigurationService::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Validators;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Form\Domain\Configuration\Exception\PropertyException;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class CollectionBasedValidator extends AbstractValidator
|
||||
{
|
||||
/**
|
||||
* Throws an exception if value from a property collection property
|
||||
* does not match its hmac hash or if there is no hmac hash
|
||||
* available for the value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @throws PropertyException
|
||||
*/
|
||||
public function validatePropertyCollectionElementPropertyValueByHmacData(
|
||||
array $currentElement,
|
||||
$value,
|
||||
string $sessionToken,
|
||||
ValidationDto $dto
|
||||
): void {
|
||||
$hmacDataPath = $this->buildHmacDataPath($dto->getPropertyPath());
|
||||
if (ArrayUtility::isValidPath($currentElement, $hmacDataPath, '.')) {
|
||||
$hmacData = ArrayUtility::getValueByPath($currentElement, $hmacDataPath, '.');
|
||||
|
||||
$hmacContent = [
|
||||
$dto->getFormElementIdentifier(),
|
||||
$dto->getPropertyCollectionName(),
|
||||
$dto->getPropertyCollectionElementIdentifier(),
|
||||
$dto->getPropertyPath(),
|
||||
];
|
||||
|
||||
if (!$this->getFormDefinitionValidationService()->isPropertyValueEqualToHistoricalValue($hmacContent, $value, $hmacData, $sessionToken)) {
|
||||
$message = 'The value "%s" of property "%s" (form element "%s" / "%s.%s") is not equal to the historical value "%s" #1528591586';
|
||||
throw new PropertyException(
|
||||
sprintf(
|
||||
$message,
|
||||
$value,
|
||||
$dto->getPropertyPath(),
|
||||
$dto->getFormElementIdentifier(),
|
||||
$dto->getPropertyCollectionName(),
|
||||
$dto->getPropertyCollectionElementIdentifier(),
|
||||
$hmacData['value'] ?? ''
|
||||
),
|
||||
1528591586
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$message = 'No hmac found for property "%s" (form element "%s" / "%s.%s") #1528591585';
|
||||
throw new PropertyException(
|
||||
sprintf(
|
||||
$message,
|
||||
$dto->getPropertyPath(),
|
||||
$dto->getFormElementIdentifier(),
|
||||
$dto->getPropertyCollectionName(),
|
||||
$dto->getPropertyCollectionElementIdentifier()
|
||||
),
|
||||
1528591585
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Validators;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Form\Domain\Configuration\Exception\PropertyException;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class CreatableFormElementPropertiesValidator extends ElementBasedValidator
|
||||
{
|
||||
/**
|
||||
* Checks if the form element property is defined within the form editor setup
|
||||
* or if the property is defined within the "predefinedDefaults" in the form editor setup
|
||||
* and the property value matches the predefined value
|
||||
* or if there is a valid hmac hash for the value.
|
||||
* If the form element property is defined within the form editor setup
|
||||
* and there is no valid hmac hash for the value
|
||||
* and is the form element property configured to only allow a limited set of values,
|
||||
* check the current (submitted) value against the allowed set of values (defined within the form setup).
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value)
|
||||
{
|
||||
$dto = $this->validationDto->withPropertyPath($key);
|
||||
|
||||
if ($this->getConfigurationService()->isFormElementPropertyDefinedInFormEditorSetup($dto)) {
|
||||
if ($this->getConfigurationService()->formElementPropertyHasLimitedAllowedValuesDefinedWithinFormEditorSetup($dto)) {
|
||||
$this->validateFormElementValue($value, $dto);
|
||||
}
|
||||
} elseif (
|
||||
$this->getConfigurationService()->isFormElementPropertyDefinedInPredefinedDefaultsInFormEditorSetup($dto)
|
||||
&& !ArrayUtility::isValidPath($this->currentElement, $this->buildHmacDataPath($dto->getPropertyPath()), '.')
|
||||
) {
|
||||
$this->validateFormElementPredefinedDefaultValue($value, $dto);
|
||||
} else {
|
||||
$this->validateFormElementPropertyValueByHmacData(
|
||||
$this->currentElement,
|
||||
$value,
|
||||
$this->sessionToken,
|
||||
$dto
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if the value from a form element property
|
||||
* does not match the default value from the form editor setup.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @throws PropertyException
|
||||
*/
|
||||
protected function validateFormElementPredefinedDefaultValue(
|
||||
$value,
|
||||
ValidationDto $dto
|
||||
): void {
|
||||
// If the form element is newly created, we have to compare the $value (form definition) with $predefinedDefaultValue (form setup)
|
||||
// to check the integrity (at this time we don't have a hmac for the $value to check the integrity)
|
||||
$predefinedDefaultValue = $this->getConfigurationService()->getFormElementPredefinedDefaultValueFromFormEditorSetup($dto);
|
||||
if ($value !== $predefinedDefaultValue) {
|
||||
$throwException = true;
|
||||
|
||||
if (is_string($predefinedDefaultValue)) {
|
||||
// Last chance:
|
||||
// Get all translations (from all backend languages) for the untranslated! $predefinedDefaultValue and
|
||||
// compare the (already translated) $value (from the form definition) against the possible
|
||||
// translations from $predefinedDefaultValue.
|
||||
// Usecase:
|
||||
// * backend language is EN
|
||||
// * open the form editor and add a ContentElement form element
|
||||
// * switch to another browser tab and change the backend language to DE
|
||||
// * clear the cache
|
||||
// * go back to the form editor and click the save button
|
||||
// Out of scope:
|
||||
// * the same scenario as above + delete the previous chosen backend language within the maintenance tool
|
||||
$untranslatedPredefinedDefaultValue = $this->getConfigurationService()->getFormElementPredefinedDefaultValueFromFormEditorSetup($dto, false);
|
||||
$translations = $this->getConfigurationService()->getAllBackendTranslationsForTranslationKey(
|
||||
$untranslatedPredefinedDefaultValue,
|
||||
$dto->getPrototypeName()
|
||||
);
|
||||
|
||||
if (in_array($value, $translations, true)) {
|
||||
$throwException = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($throwException) {
|
||||
$message = 'The value "%s" of property "%s" (form element "%s") is not equal to the default value "%s" #1528588035';
|
||||
throw new PropertyException(
|
||||
sprintf(
|
||||
$message,
|
||||
$value,
|
||||
$dto->getPropertyPath(),
|
||||
$dto->getFormElementIdentifier(),
|
||||
$predefinedDefaultValue
|
||||
),
|
||||
1528588035
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if the value from a form element property
|
||||
* does not match the allowed set of values (defined within the form setup).
|
||||
*
|
||||
* @param mixed $value
|
||||
* @throws PropertyException
|
||||
*/
|
||||
protected function validateFormElementValue(
|
||||
$value,
|
||||
ValidationDto $dto
|
||||
): void {
|
||||
$allowedValues = $this->getConfigurationService()->getAllowedValuesForFormElementPropertyFromFormEditorSetup($dto);
|
||||
|
||||
if (!in_array($value, $allowedValues, true)) {
|
||||
$untranslatedAllowedValues = $this->getConfigurationService()->getAllowedValuesForFormElementPropertyFromFormEditorSetup($dto, false);
|
||||
// Compare the $value against the untranslated set of allowed values
|
||||
if (in_array($value, $untranslatedAllowedValues, true)) {
|
||||
// All good, $value is within the untranslated set of allowed values
|
||||
return;
|
||||
}
|
||||
// Get all translations (from all backend languages) for the untranslated! $allowedValues and
|
||||
// compare the (already translated) $value (from the form definition) against all possible
|
||||
// translations for $untranslatedAllowedValues.
|
||||
$allPossibleAllowedValuesTranslations = $this->getConfigurationService()->getAllBackendTranslationsForTranslationKeys(
|
||||
$untranslatedAllowedValues,
|
||||
$dto->getPrototypeName()
|
||||
);
|
||||
|
||||
foreach ($allPossibleAllowedValuesTranslations as $translations) {
|
||||
if (in_array($value, $translations, true)) {
|
||||
// All good, $value is within the set of translated allowed values
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Last chance:
|
||||
// If $value is not configured within the form setup as an allowed value
|
||||
// but was written within the form definition by hand (and therefore contains a hmac),
|
||||
// check if $value is manipulated.
|
||||
// If $value has no hmac or if the hmac exists but is not valid,
|
||||
// then $this->validatePropertyCollectionElementPropertyValueByHmacData() will
|
||||
// throw an exception.
|
||||
$this->validateFormElementPropertyValueByHmacData(
|
||||
$this->currentElement,
|
||||
$value,
|
||||
$this->sessionToken,
|
||||
$dto
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Validators;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Form\Domain\Configuration\Exception\PropertyException;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class CreatablePropertyCollectionElementPropertiesValidator extends CollectionBasedValidator
|
||||
{
|
||||
/**
|
||||
* Checks if the property collection element property is defined
|
||||
* within the form editor setup or if the property is defined within
|
||||
* the "predefinedDefaults" in the form editor setup
|
||||
* and the property value matches the predefined value
|
||||
* or if there is a valid hmac hash for the value.
|
||||
* If the property collection element property is defined within the form editor setup
|
||||
* and there is no valid hmac hash for the value
|
||||
* and is the form property collection element property configured to only allow a limited set of values,
|
||||
* check the current (submitted) value against the allowed set of values (defined within the form setup).
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value)
|
||||
{
|
||||
$dto = $this->validationDto->withPropertyPath($key);
|
||||
|
||||
if ($this->getConfigurationService()->isPropertyCollectionPropertyDefinedInFormEditorSetup($dto)) {
|
||||
if ($this->getConfigurationService()->propertyCollectionPropertyHasLimitedAllowedValuesDefinedWithinFormEditorSetup($dto)) {
|
||||
$this->validatePropertyCollectionPropertyValue($value, $dto);
|
||||
}
|
||||
} elseif (
|
||||
$this->getConfigurationService()->isPropertyCollectionPropertyDefinedInPredefinedDefaultsInFormEditorSetup($dto)
|
||||
&& !ArrayUtility::isValidPath($this->currentElement, $this->buildHmacDataPath($dto->getPropertyPath()), '.')
|
||||
) {
|
||||
$this->validatePropertyCollectionElementPredefinedDefaultValue($value, $dto);
|
||||
} else {
|
||||
$this->validatePropertyCollectionElementPropertyValueByHmacData(
|
||||
$this->currentElement,
|
||||
$value,
|
||||
$this->sessionToken,
|
||||
$dto
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if the value from a property collection property
|
||||
* does not match the default value from the form editor setup.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @throws PropertyException
|
||||
*/
|
||||
protected function validatePropertyCollectionElementPredefinedDefaultValue(
|
||||
$value,
|
||||
ValidationDto $dto
|
||||
): void {
|
||||
// If the property collection element is newly created, we have to compare the $value (form definition) with $predefinedDefaultValue (form setup)
|
||||
// to check the integrity (at this time we don't have a hmac on the value to check the integrity)
|
||||
$predefinedDefaultValue = $this->getConfigurationService()->getPropertyCollectionPredefinedDefaultValueFromFormEditorSetup($dto);
|
||||
if ($value !== $predefinedDefaultValue) {
|
||||
$throwException = true;
|
||||
|
||||
if (is_string($predefinedDefaultValue)) {
|
||||
// Last chance:
|
||||
// Get all translations (from all backend languages) for the untranslated! $predefinedDefaultValue and
|
||||
// compare the (already translated) $value (from the form definition) against the possible
|
||||
// translations from $predefinedDefaultValue.
|
||||
$untranslatedPredefinedDefaultValue = $this->getConfigurationService()->getPropertyCollectionPredefinedDefaultValueFromFormEditorSetup($dto, false);
|
||||
$translations = $this->getConfigurationService()->getAllBackendTranslationsForTranslationKey(
|
||||
$untranslatedPredefinedDefaultValue,
|
||||
$dto->getPrototypeName()
|
||||
);
|
||||
|
||||
if (in_array($value, $translations, true)) {
|
||||
$throwException = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($throwException) {
|
||||
$message = 'The value "%s" of property "%s" (form element "%s" / "%s.%s") is not equal to the default value "%s" #1528591502';
|
||||
throw new PropertyException(
|
||||
sprintf(
|
||||
$message,
|
||||
$value,
|
||||
$dto->getPropertyPath(),
|
||||
$dto->getFormElementIdentifier(),
|
||||
$dto->getPropertyCollectionName(),
|
||||
$dto->getPropertyCollectionElementIdentifier(),
|
||||
$predefinedDefaultValue
|
||||
),
|
||||
1528591502
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if the value from a property collection property
|
||||
* does not match the allowed set of values (defined within the form setup).
|
||||
*
|
||||
* @param mixed $value
|
||||
* @throws PropertyException
|
||||
*/
|
||||
protected function validatePropertyCollectionPropertyValue(
|
||||
$value,
|
||||
ValidationDto $dto
|
||||
): void {
|
||||
$allowedValues = $this->getConfigurationService()->getAllowedValuesForPropertyCollectionPropertyFromFormEditorSetup($dto);
|
||||
|
||||
if (!in_array($value, $allowedValues, true)) {
|
||||
$untranslatedAllowedValues = $this->getConfigurationService()->getAllowedValuesForPropertyCollectionPropertyFromFormEditorSetup($dto, false);
|
||||
// Compare the $value against the untranslated set of allowed values
|
||||
if (in_array($value, $untranslatedAllowedValues, true)) {
|
||||
// All good, $value is within the untranslated set of allowed values
|
||||
return;
|
||||
}
|
||||
// Get all translations (from all backend languages) for the untranslated! $allowedValues and
|
||||
// compare the (already translated) $value (from the form definition) against all possible
|
||||
// translations for $untranslatedAllowedValues.
|
||||
$allPossibleAllowedValuesTranslations = $this->getConfigurationService()->getAllBackendTranslationsForTranslationKeys(
|
||||
$untranslatedAllowedValues,
|
||||
$dto->getPrototypeName()
|
||||
);
|
||||
|
||||
foreach ($allPossibleAllowedValuesTranslations as $translations) {
|
||||
if (in_array($value, $translations, true)) {
|
||||
// All good, $value is within the set of translated allowed values
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Last chance:
|
||||
// If $value is not configured within the form setup as an allowed value
|
||||
// but was written within the form definition by hand (and therefore contains a hmac),
|
||||
// check if $value is manipulated.
|
||||
// If $value has no hmac or if the hmac exists but is not valid,
|
||||
// then $this->validatePropertyCollectionElementPropertyValueByHmacData() will
|
||||
// throw an exception.
|
||||
$this->validatePropertyCollectionElementPropertyValueByHmacData(
|
||||
$this->currentElement,
|
||||
$value,
|
||||
$this->sessionToken,
|
||||
$dto
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Validators;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Form\Domain\Configuration\Exception\PropertyException;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class ElementBasedValidator extends AbstractValidator
|
||||
{
|
||||
/**
|
||||
* Throws an exception if value from a form element property
|
||||
* does not match its hmac hash or if there is no hmac hash
|
||||
* available for the value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @throws PropertyException
|
||||
*/
|
||||
public function validateFormElementPropertyValueByHmacData(
|
||||
array $currentElement,
|
||||
$value,
|
||||
string $sessionToken,
|
||||
ValidationDto $dto
|
||||
): void {
|
||||
$hmacDataPath = $this->buildHmacDataPath($dto->getPropertyPath());
|
||||
if (ArrayUtility::isValidPath($currentElement, $hmacDataPath, '.')) {
|
||||
$hmacData = ArrayUtility::getValueByPath($currentElement, $hmacDataPath, '.');
|
||||
|
||||
$hmacContent = [$dto->getFormElementIdentifier(), $dto->getPropertyPath()];
|
||||
if (!$this->getFormDefinitionValidationService()->isPropertyValueEqualToHistoricalValue($hmacContent, $value, $hmacData, $sessionToken)) {
|
||||
$message = 'The value "%s" of property "%s" (form element "%s") is not equal to the historical value "%s" #1528588036';
|
||||
throw new PropertyException(
|
||||
sprintf(
|
||||
$message,
|
||||
$value,
|
||||
$dto->getPropertyPath(),
|
||||
$dto->getFormElementIdentifier(),
|
||||
$hmacData['value'] ?? ''
|
||||
),
|
||||
1528588036
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$message = 'No hmac found for property "%s" (form element "%s") #1528588037';
|
||||
throw new PropertyException(
|
||||
sprintf($message, $dto->getPropertyPath(), $dto->getFormElementIdentifier()),
|
||||
1528588037
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Validators;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class FormElementHmacDataValidator extends ElementBasedValidator
|
||||
{
|
||||
/**
|
||||
* Checks if the form element property value matches to its hmac hash.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value): void
|
||||
{
|
||||
$dto = $this->validationDto->withPropertyPath($key);
|
||||
$this->validateFormElementPropertyValueByHmacData(
|
||||
$this->currentElement,
|
||||
$value,
|
||||
$this->sessionToken,
|
||||
$dto
|
||||
);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Validators;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class PropertyCollectionElementHmacDataValidator extends CollectionBasedValidator
|
||||
{
|
||||
/**
|
||||
* Checks if the property collection element values matches to its hmac hash.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value): void
|
||||
{
|
||||
$dto = $this->validationDto->withPropertyPath($key)->withPropertyCollectionElementIdentifier(
|
||||
$this->currentElement['identifier']
|
||||
);
|
||||
$this->validatePropertyCollectionElementPropertyValueByHmacData(
|
||||
$this->currentElement,
|
||||
$value,
|
||||
$this->sessionToken,
|
||||
$dto
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Validators;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class ValidationDto
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $prototypeName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $formElementType;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $formElementIdentifier;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $propertyPath;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $propertyCollectionName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $propertyCollectionElementIdentifier;
|
||||
|
||||
public function __construct(
|
||||
?string $prototypeName = null,
|
||||
?string $formElementType = null,
|
||||
?string $formElementIdentifier = null,
|
||||
?string $propertyPath = null,
|
||||
?string $propertyCollectionName = null,
|
||||
?string $propertyCollectionElementIdentifier = null
|
||||
) {
|
||||
$this->prototypeName = $prototypeName;
|
||||
$this->formElementType = $formElementType;
|
||||
$this->formElementIdentifier = $formElementIdentifier;
|
||||
$this->propertyPath = $propertyPath;
|
||||
$this->propertyCollectionName = $propertyCollectionName;
|
||||
$this->propertyCollectionElementIdentifier = $propertyCollectionElementIdentifier;
|
||||
}
|
||||
|
||||
public function getPrototypeName(): string
|
||||
{
|
||||
return $this->prototypeName;
|
||||
}
|
||||
|
||||
public function getFormElementType(): string
|
||||
{
|
||||
return $this->formElementType;
|
||||
}
|
||||
|
||||
public function getFormElementIdentifier(): string
|
||||
{
|
||||
return $this->formElementIdentifier;
|
||||
}
|
||||
|
||||
public function getPropertyPath(): string
|
||||
{
|
||||
return $this->propertyPath;
|
||||
}
|
||||
|
||||
public function getPropertyCollectionName(): string
|
||||
{
|
||||
return $this->propertyCollectionName;
|
||||
}
|
||||
|
||||
public function getPropertyCollectionElementIdentifier(): string
|
||||
{
|
||||
return $this->propertyCollectionElementIdentifier;
|
||||
}
|
||||
|
||||
public function hasPrototypeName(): bool
|
||||
{
|
||||
return !empty($this->prototypeName);
|
||||
}
|
||||
|
||||
public function hasFormElementType(): bool
|
||||
{
|
||||
return !empty($this->formElementType);
|
||||
}
|
||||
|
||||
public function hasFormElementIdentifier(): bool
|
||||
{
|
||||
return !empty($this->formElementIdentifier);
|
||||
}
|
||||
|
||||
public function hasPropertyPath(): bool
|
||||
{
|
||||
return !empty($this->propertyPath);
|
||||
}
|
||||
|
||||
public function hasPropertyCollectionName(): bool
|
||||
{
|
||||
return !empty($this->propertyCollectionName);
|
||||
}
|
||||
|
||||
public function hasPropertyCollectionElementIdentifier(): bool
|
||||
{
|
||||
return !empty($this->propertyCollectionElementIdentifier);
|
||||
}
|
||||
|
||||
public function withPrototypeName(string $prototypeName): ValidationDto
|
||||
{
|
||||
return GeneralUtility::makeInstance(self::class, $prototypeName, $this->formElementType, $this->formElementIdentifier, $this->propertyPath, $this->propertyCollectionName, $this->propertyCollectionElementIdentifier);
|
||||
}
|
||||
|
||||
public function withFormElementType(string $formElementType): ValidationDto
|
||||
{
|
||||
return GeneralUtility::makeInstance(self::class, $this->prototypeName, $formElementType, $this->formElementIdentifier, $this->propertyPath, $this->propertyCollectionName, $this->propertyCollectionElementIdentifier);
|
||||
}
|
||||
|
||||
public function withFormElementIdentifier(string $formElementIdentifier): ValidationDto
|
||||
{
|
||||
return GeneralUtility::makeInstance(self::class, $this->prototypeName, $this->formElementType, $formElementIdentifier, $this->propertyPath, $this->propertyCollectionName, $this->propertyCollectionElementIdentifier);
|
||||
}
|
||||
|
||||
public function withPropertyPath(string $propertyPath): ValidationDto
|
||||
{
|
||||
return GeneralUtility::makeInstance(self::class, $this->prototypeName, $this->formElementType, $this->formElementIdentifier, $propertyPath, $this->propertyCollectionName, $this->propertyCollectionElementIdentifier);
|
||||
}
|
||||
|
||||
public function withPropertyCollectionName(string $propertyCollectionName): ValidationDto
|
||||
{
|
||||
return GeneralUtility::makeInstance(self::class, $this->prototypeName, $this->formElementType, $this->formElementIdentifier, $this->propertyPath, $propertyCollectionName, $this->propertyCollectionElementIdentifier);
|
||||
}
|
||||
|
||||
public function withPropertyCollectionElementIdentifier(string $propertyCollectionElementIdentifier): ValidationDto
|
||||
{
|
||||
return GeneralUtility::makeInstance(self::class, $this->prototypeName, $this->formElementType, $this->formElementIdentifier, $this->propertyPath, $this->propertyCollectionName, $propertyCollectionElementIdentifier);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Form\Domain\Configuration\FormDefinition\Validators;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface ValidatorInterface
|
||||
{
|
||||
public function __construct(array $currentElement, string $sessionToken, ValidationDto $validationDto);
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __invoke(string $key, $value);
|
||||
}
|
||||
Reference in New Issue
Block a user