configurationService->isFormElementTypeCreatableByFormEditor($validationDto)) { $this->validateAllPropertyValuesFromCreatableFormElement( $currentFormElement, $sessionToken, $validationDto ); foreach ($propertyCollectionElements as $propertyCollectionElement) { $validationDto = $validationDto->withPropertyCollectionElementIdentifier( $propertyCollectionElement['identifier'] ); if ($this->configurationService->isPropertyCollectionElementIdentifierCreatableByFormEditor($validationDto)) { $this->validateAllPropertyValuesFromCreatablePropertyCollectionElement( $propertyCollectionElement, $sessionToken, $validationDto ); } else { $this->validateAllPropertyCollectionElementValuesByHmac( $propertyCollectionElement, $sessionToken, $validationDto ); } } } else { $this->validateAllFormElementPropertyValuesByHmac($currentFormElement, $sessionToken, $validationDto); foreach ($propertyCollectionElements as $propertyCollectionElement) { $this->validateAllPropertyCollectionElementValuesByHmac( $propertyCollectionElement, $sessionToken, $validationDto ); } } foreach ($renderables as $renderable) { $this->validateFormDefinitionProperties($renderable, $prototypeName, $sessionToken); } } /** * Returns TRUE if a property value is equals to the historical value * and FALSE if not. * "Historical values" means values which are available within the form definition * while the form editor is loaded and the values which are available after a * successful validation of the form definition on a save operation. * The value must be equal to the historical value if the property key for the value * is not defined within the form setup. * This means that the property can not be changed by the form editor but we want to keep the value * in its original state. * If this is not the case (return value is FALSE), an exception must be thrown. * * @throws PropertyException */ public function isPropertyValueEqualToHistoricalValue( array $hmacContent, mixed $propertyValue, array $hmacData, string $sessionToken ): bool { $this->checkHmacDataIntegrity($hmacData, $hmacContent, $sessionToken); $hmacContent[] = $propertyValue; $expectedHash = $this->hashService->hmac(serialize($hmacContent), $sessionToken); return hash_equals($expectedHash, $hmacData['hmac']); } /** * Compares the historical value and the hmac hash to ensure the integrity * of the data. * An exception will be thrown if the value is modified. * * @throws PropertyException */ protected function checkHmacDataIntegrity(array $hmacData, array $hmacContent, string $sessionToken) { $hmac = $hmacData['hmac'] ?? null; if (empty($hmac)) { throw new PropertyException('Hmac must not be empty. #1528538222', 1528538222); } $hmacContent[] = $hmacData['value'] ?? ''; $expectedHash = $this->hashService->hmac(serialize($hmacContent), $sessionToken); if (!hash_equals($expectedHash, $hmac)) { throw new PropertyException('Unauthorized modification of historical data. #1528538252', 1528538252); } } /** * Walk through all form element properties and checks * if the values matches to their hmac hashes. */ protected function validateAllFormElementPropertyValuesByHmac( array $currentElement, string $sessionToken, ValidationDto $validationDto ): void { GeneralUtility::makeInstance(ArrayProcessor::class, $currentElement)->forEach( GeneralUtility::makeInstance( ArrayProcessing::class, 'validateProperties', '^(?!(_orig_.*|.*\._orig_.*)$).*', GeneralUtility::makeInstance( FormElementHmacDataValidator::class, $currentElement, $sessionToken, $validationDto ) ) ); } /** * Walk through all property collection properties and checks * if the values matches to their hmac hashes. */ protected function validateAllPropertyCollectionElementValuesByHmac( array $currentElement, string $sessionToken, ValidationDto $validationDto ): void { GeneralUtility::makeInstance(ArrayProcessor::class, $currentElement)->forEach( GeneralUtility::makeInstance( ArrayProcessing::class, 'validateProperties', '^(?!(_orig_.*|.*\._orig_.*)$).*', GeneralUtility::makeInstance( PropertyCollectionElementHmacDataValidator::class, $currentElement, $sessionToken, $validationDto ) ) ); } /** * Walk through all form element properties and checks * if the 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. */ protected function validateAllPropertyValuesFromCreatableFormElement( array $currentElement, string $sessionToken, ValidationDto $validationDto ): void { GeneralUtility::makeInstance(ArrayProcessor::class, $currentElement)->forEach( GeneralUtility::makeInstance( ArrayProcessing::class, 'validateProperties', '^(?!(_orig_.*|.*\._orig_.*|type|identifier)$).*', GeneralUtility::makeInstance( CreatableFormElementPropertiesValidator::class, $currentElement, $sessionToken, $validationDto ) ) ); } /** * Walk through all property collection properties and checks * if the 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. */ protected function validateAllPropertyValuesFromCreatablePropertyCollectionElement( array $currentElement, string $sessionToken, ValidationDto $validationDto ): void { GeneralUtility::makeInstance(ArrayProcessor::class, $currentElement)->forEach( GeneralUtility::makeInstance( ArrayProcessing::class, 'validateProperties', '^(?!(_orig_.*|.*\._orig_.*|identifier)$).*', GeneralUtility::makeInstance( CreatablePropertyCollectionElementPropertiesValidator::class, $currentElement, $sessionToken, $validationDto ) ) ); } }