isImporting || $parent->bypassAccessCheckForRecords; if ($table === 'sys_file' && !$isInternalProcess) { $accessAllowed = false; } } /** * Checks file related data being processed in `DataHandler`: * + `sys_file` (only if `checkModifyAccessList` passed -> during internal process) * + `sys_file_reference` * + `sys_file_metadata` * * @param mixed $incomingFieldArray * @param string $table * @param DataHandler $dataHandler */ public function processDatamap_preProcessFieldArray(&$incomingFieldArray, string $table, int|string $id, DataHandler $dataHandler): void { if (!is_array($incomingFieldArray)) { $incomingFieldArray = null; return; } $isInternalProcess = $dataHandler->isImporting || $dataHandler->bypassAccessCheckForRecords; $isNew = !MathUtility::canBeInterpretedAsInteger($id); $logId = $isNew ? 0 : (int)$id; if ($table === 'sys_file') { $file = $this->resolveFile((int)$id); if (!$this->isValidStorageData($incomingFieldArray) || (!$isNew && $file !== null && $this->usesLegacyStorage($file)) ) { $incomingFieldArray = null; $this->logError($table, $logId, 'Attempt to set legacy storage directly is disallowed', $dataHandler); } } elseif ($table === 'sys_file_reference') { $files = $this->resolveReferencedFiles($incomingFieldArray, 'uid_local'); foreach ($files as $file) { if ($file === null) { $incomingFieldArray = null; $this->logError($table, $logId, 'Attempt to reference invalid file is disallowed', $dataHandler); } elseif ($this->usesLegacyStorage($file)) { $incomingFieldArray = null; $this->logError($table, $logId, sprintf('Attempt to reference file "%d" in legacy storage is disallowed', $file->getUid()), $dataHandler); } elseif (!$isInternalProcess && $this->usesDisallowedFileMount($file, 'read', $dataHandler->BE_USER)) { $incomingFieldArray = null; $this->logError($table, $logId, sprintf('Attempt to reference file "%d" without permission is disallowed', $file->getUid()), $dataHandler); } } } elseif ($table === 'sys_file_metadata') { $file = $this->resolveReferencedFile($incomingFieldArray, 'file'); if ($file !== null && $this->usesLegacyStorage($file)) { $incomingFieldArray = null; $this->logError($table, $logId, sprintf('Attempt to alter metadata of file "%d" in legacy storage is disallowed', $file->getUid()), $dataHandler); } elseif (!$isInternalProcess && $file !== null && $this->usesDisallowedFileMount($file, 'editMeta', $dataHandler->BE_USER)) { $incomingFieldArray = null; $this->logError($table, $logId, sprintf('Attempt to alter metadata of file "%d" without permission is disallowed', $file->getUid()), $dataHandler); } } } protected function logError(string $table, int $id, string $message, DataHandler $dataHandler): void { $dataHandler->log( $table, $id, SystemLogDatabaseAction::UPDATE, null, SystemLogErrorClassification::USER_ERROR, $message, null, [$table] ); } protected function usesLegacyStorage(File $file): bool { return $file->getStorage()->getUid() === 0; } /** * @param non-empty-string $fileAction * @param BackendUserAuthentication|mixed $backendUser */ protected function usesDisallowedFileMount(File $file, string $fileAction, mixed $backendUser): bool { // strict: disallow, in case it cannot be determined from BE_USER if (!$backendUser instanceof BackendUserAuthentication) { return true; } foreach ($backendUser->getFileStorages() as $storage) { if ($storage->getUid() === $file->getStorage()->getUid()) { return !$storage->checkFileActionPermission($fileAction, $file); } } return false; } /** * @return list */ protected function resolveReferencedFiles(array $data, string $propertyName): array { $propertyItems = GeneralUtility::trimExplode(',', (string)($data[$propertyName] ?? ''), true); return array_map( function (string $item): ?File { if (MathUtility::canBeInterpretedAsInteger($item)) { return $this->resolveFile((int)$item); } if (preg_match('/^sys_file_(?P\d+)$/', $item, $matches) && (int)$matches['fileId'] > 0) { return $this->resolveFile((int)$matches['fileId']); } return null; }, $propertyItems ); } protected function resolveReferencedFile(array $data, string $propertyName): ?File { $propertyValue = $data[$propertyName] ?? null; if ($propertyValue === null || !MathUtility::canBeInterpretedAsInteger($propertyValue)) { return null; } return $this->resolveFile((int)$propertyValue); } protected function resolveFile(int $fileId): ?File { try { return $this->resourceFactory->getFileObject($fileId); } catch (\Throwable $t) { return null; } } protected function isValidStorageData(array $data): bool { $storage = $data['storage'] ?? ''; if (!MathUtility::canBeInterpretedAsInteger($storage)) { return false; } return (int)$storage > 0; } }