diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..2747591 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +/Tests/ export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/.gitignore b/.gitignore index a18580d..b35aa4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ +.DS_Store +.build .idea/ /out/ +vendor/ .idea_modules/ atlassian-ide-plugin.xml com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties +composer.lock composer.phar -/vendor/ diff --git a/Classes/Hooks/DataHandlerHook.php b/Classes/Hooks/DataHandlerHook.php new file mode 100644 index 0000000..be9ad6e --- /dev/null +++ b/Classes/Hooks/DataHandlerHook.php @@ -0,0 +1,44 @@ +isSvgFile($filename)) { + $svgService->sanitizeSvgFile($filename); + } + } +} diff --git a/Classes/Hooks/GeneralUtilityHook.php b/Classes/Hooks/GeneralUtilityHook.php new file mode 100644 index 0000000..44f1854 --- /dev/null +++ b/Classes/Hooks/GeneralUtilityHook.php @@ -0,0 +1,49 @@ +isSvgFile($filename)) { + $svgService->sanitizeSvgFile($filename); + } + } +} diff --git a/Classes/Service/SvgSanitizerService.php b/Classes/Service/SvgSanitizerService.php new file mode 100644 index 0000000..80af18f --- /dev/null +++ b/Classes/Service/SvgSanitizerService.php @@ -0,0 +1,72 @@ +getMimeType(), ['image/svg+xml', 'application/svg+xml'], true); + } + + /** + * @param string $fileNameAndPath + * @param string $outputFileNameAndPath + * @throws \BadFunctionCallException + */ + public function sanitizeSvgFile($fileNameAndPath, $outputFileNameAndPath = null) + { + if ($outputFileNameAndPath === null) { + $outputFileNameAndPath = $fileNameAndPath; + } + $dirtySVG = file_get_contents($fileNameAndPath); + $cleanSVG = $this->sanitizeAndReturnSvgContent($dirtySVG); + if ($cleanSVG !== $dirtySVG) { + file_put_contents($outputFileNameAndPath, $cleanSVG); + } + } + + /** + * @param string $dirtySVG + * + * @return string + * @throws \BadFunctionCallException + */ + public function sanitizeAndReturnSvgContent($dirtySVG) + { + $extensionBasePath = ExtensionManagementUtility::extPath('svg_sanitizer'); + if (!class_exists(Sanitizer::class)) { + @include 'phar://' . $extensionBasePath . 'Libraries/enshrined-svg-sanitize.phar/vendor/autoload.php'; + } + $sanitizer = new Sanitizer(); + $sanitizer->removeRemoteReferences(true); + return $sanitizer->sanitize($dirtySVG); + } +} diff --git a/Classes/Service/UpdateService.php b/Classes/Service/UpdateService.php new file mode 100644 index 0000000..774371e --- /dev/null +++ b/Classes/Service/UpdateService.php @@ -0,0 +1,56 @@ +getQueryBuilderForTable('sys_file_storage'); + $rows = $queryBuilder + ->select('uid') + ->from('sys_file_storage') + ->where($queryBuilder->expr()->eq('is_writable', 1)) + ->execute() + ->fetchAll(); + + $resourceFactory = ResourceFactory::getInstance(); + foreach ($rows as $row) { + $filter = GeneralUtility::makeInstance(FileExtensionFilter::class); + $filter->setAllowedFileExtensions(['svg']); + + $storage = $resourceFactory->getStorageObject((int)$row['uid']); + $storage->setFileAndFolderNameFilters([[$filter, 'filterFileList']]); + $files = $storage->getFilesInFolder($storage->getRootLevelFolder(), 0, 0, true, true); + + $svgSanitizerService = GeneralUtility::makeInstance(SvgSanitizerService::class); + foreach ($files as $file) { + $oldFileContent = $file->getContents(); + $newFileContent = $svgSanitizerService->sanitizeAndReturnSvgContent($oldFileContent); + if ($oldFileContent !== $newFileContent) { + $file->setContents($newFileContent); + } + } + } + return true; + } +} diff --git a/Classes/SignalSlot/ResourceStorage.php b/Classes/SignalSlot/ResourceStorage.php new file mode 100644 index 0000000..467f65c --- /dev/null +++ b/Classes/SignalSlot/ResourceStorage.php @@ -0,0 +1,78 @@ +isSvgFile($sourceFilePath)) { + $svgService->sanitizeSvgFile($sourceFilePath); + } + } + + /** + * @param FileInterface $file + * @param string $localFilePath + * + * @throws \InvalidArgumentException + */ + public function preFileReplace($file, $localFilePath) + { + $svgService = GeneralUtility::makeInstance(SvgSanitizerService::class); + if ($svgService->isSvgFile($localFilePath)) { + $svgService->sanitizeSvgFile($localFilePath); + } + } + + /** + * @param FileInterface $file + * @param string $content + * + * @throws \InvalidArgumentException + */ + public function postFileSetContents($file, $content) + { + $svgService = GeneralUtility::makeInstance(SvgSanitizerService::class); + if ($svgService->isSvgFile($file->getForLocalProcessing(false))) { + $newContent = $svgService->sanitizeAndReturnSvgContent($content); + // prevent endless loop because this hook is called again and again and again and... + if ($newContent !== $content) { + $file->setContents($newContent); + } + } + } +} diff --git a/Classes/Updates/v8/SanitizeExistingSVG.php b/Classes/Updates/v8/SanitizeExistingSVG.php new file mode 100644 index 0000000..38af7ab --- /dev/null +++ b/Classes/Updates/v8/SanitizeExistingSVG.php @@ -0,0 +1,103 @@ +isWizardDone()) { + return false; + } + return true; + } + + /** + * Second step: Ask user to sanitize existing SVG files + * + * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ] + * @return string HTML output + */ + public function getUserInput($inputPrefix) + { + $markup = []; + $markup[] = '
This upgrade wizard will sanitize all SVG file in the fileadmin folder.
'; + $markup[] = 'This means that the content of your SVG files will be changed. This automatic process can break your SVG files.
'; + $markup[] = 'PLEASE: Create a backup of your SVG files, before starting this wizard!
'; + $markup[] = 'Are you really sure, you want to do this now?
'; + $markup[] = '