diff --git a/Neos.Media.Browser/Classes/Controller/AssetController.php b/Neos.Media.Browser/Classes/Controller/AssetController.php index a4ee773a8ca..0446964cd1f 100644 --- a/Neos.Media.Browser/Classes/Controller/AssetController.php +++ b/Neos.Media.Browser/Classes/Controller/AssetController.php @@ -14,6 +14,7 @@ use Doctrine\Common\Persistence\Proxy as DoctrineProxy; use Doctrine\ORM\EntityNotFoundException; +use enshrined\svgSanitize\Sanitizer; use Neos\Error\Messages\Error; use Neos\Error\Messages\Message; use Neos\Flow\Annotations as Flow; @@ -35,6 +36,7 @@ use Neos\Media\Domain\Model\AssetCollection; use Neos\Media\Domain\Model\AssetInterface; use Neos\Media\Domain\Model\AssetSource\AssetNotFoundExceptionInterface; +use Neos\Media\Domain\Model\AssetSource\AssetProxy\AssetProxyInterface; use Neos\Media\Domain\Model\AssetSource\AssetProxyRepositoryInterface; use Neos\Media\Domain\Model\AssetSource\AssetSourceConnectionExceptionInterface; use Neos\Media\Domain\Model\AssetSource\AssetSourceInterface; @@ -372,7 +374,8 @@ public function showAction(string $assetSourceIdentifier, string $assetProxyIden $this->view->assignMultiple([ 'assetProxy' => $assetProxy, - 'assetCollections' => $this->assetCollectionRepository->findAll() + 'assetCollections' => $this->assetCollectionRepository->findAll(), + 'assetContainsMaliciousContent' => $this->checkForMaliciousContent($assetProxy) ]); } catch (AssetNotFoundExceptionInterface | AssetSourceConnectionExceptionInterface $e) { $this->view->assign('connectionError', $e); @@ -425,6 +428,7 @@ public function editAction(string $assetSourceIdentifier, string $assetProxyIden 'assetCollections' => $this->assetCollectionRepository->findAll(), 'contentPreview' => $contentPreview, 'assetSource' => $assetSource, + 'assetContainsMaliciousContent' => $this->checkForMaliciousContent($assetProxy), 'canShowVariants' => ($assetProxy instanceof NeosAssetProxy) && ($assetProxy->getAsset() instanceof VariantSupportInterface) ]); } catch (AssetNotFoundExceptionInterface | AssetSourceConnectionExceptionInterface $e) { @@ -1024,4 +1028,25 @@ private function forwardWithConstraints(string $actionName, string $controllerNa } $this->forward($actionName, $controllerName, null, $arguments); } + + private function checkForMaliciousContent(AssetProxyInterface $assetProxy): bool + { + if ($assetProxy->getMediaType() == 'image/svg+xml') { + // @todo: Simplify again when https://github.com/darylldoyle/svg-sanitizer/pull/90 is merged and released. + $previousXmlErrorHandling = libxml_use_internal_errors(true); + $sanitizer = new Sanitizer(); + + $resource = stream_get_contents($assetProxy->getImportStream()); + + $sanitizer->sanitize($resource); + libxml_clear_errors(); + libxml_use_internal_errors($previousXmlErrorHandling); + $issues = $sanitizer->getXmlIssues(); + if ($issues && count($issues) > 0) { + return true; + } + } + + return false; + } } diff --git a/Neos.Media.Browser/Resources/Private/Partials/ContentDefaultPreview.html b/Neos.Media.Browser/Resources/Private/Partials/ContentDefaultPreview.html index f32baac89dd..3f0963cdf42 100644 --- a/Neos.Media.Browser/Resources/Private/Partials/ContentDefaultPreview.html +++ b/Neos.Media.Browser/Resources/Private/Partials/ContentDefaultPreview.html @@ -1,7 +1,14 @@ {namespace m=Neos\Media\ViewHelpers} {namespace neos=Neos\Neos\ViewHelpers}
- - {assetProxy.label} - + + + {assetProxy.label} + + + + {assetProxy.label} + + +
diff --git a/Neos.Media.Browser/Resources/Private/Templates/Asset/Edit.html b/Neos.Media.Browser/Resources/Private/Templates/Asset/Edit.html index f40c47e7df1..06ec12fa5d7 100644 --- a/Neos.Media.Browser/Resources/Private/Templates/Asset/Edit.html +++ b/Neos.Media.Browser/Resources/Private/Templates/Asset/Edit.html @@ -78,7 +78,19 @@

{neos:backend.translate(id: 'connectionError', package: 'Neos.Media.Browser' {neos:backend.translate(id: 'metadata.filename', package: 'Neos.Media.Browser')} - {assetProxy.filename} + + + + {assetProxy.filename} +
+ {neos:backend.translate(id: 'message.assetContainsMaliciousContent', package: 'Neos.Media.Browser')} +
+
+ + {assetProxy.filename} + +
+ {neos:backend.translate(id: 'metadata.lastModified', package: 'Neos.Media.Browser')} diff --git a/Neos.Media.Browser/Resources/Private/Templates/Asset/Show.html b/Neos.Media.Browser/Resources/Private/Templates/Asset/Show.html index 0375e584638..c74719983bb 100644 --- a/Neos.Media.Browser/Resources/Private/Templates/Asset/Show.html +++ b/Neos.Media.Browser/Resources/Private/Templates/Asset/Show.html @@ -39,7 +39,19 @@ {neos:backend.translate(id: 'metadata.filename', package: 'Neos.Media.Browser')} - {assetProxy.filename} + + + + {assetProxy.filename} +
+ {neos:backend.translate(id: 'message.assetContainsMaliciousContent', package: 'Neos.Media.Browser')} +
+
+ + {assetProxy.filename} + +
+ {neos:backend.translate(id: 'metadata.lastModified', package: 'Neos.Media.Browser')} @@ -85,9 +97,16 @@
- - {assetProxy.label} - + + + {assetProxy.label} + + + + {assetProxy.label} + + +
diff --git a/Neos.Media.Browser/Resources/Private/Translations/en/Main.xlf b/Neos.Media.Browser/Resources/Private/Translations/en/Main.xlf index 07f3354ed02..1dd0ef007a1 100644 --- a/Neos.Media.Browser/Resources/Private/Translations/en/Main.xlf +++ b/Neos.Media.Browser/Resources/Private/Translations/en/Main.xlf @@ -101,6 +101,9 @@ This operation cannot be undone. + + This asset might contain malicious content! + Cancel diff --git a/Neos.Media.Browser/composer.json b/Neos.Media.Browser/composer.json index 3d9991f6e0e..494fd4f244b 100644 --- a/Neos.Media.Browser/composer.json +++ b/Neos.Media.Browser/composer.json @@ -12,6 +12,7 @@ ], "require": { "php": "^8.0", + "ext-libxml": "*", "neos/media": "self.version", "neos/content-repository": "self.version", "neos/neos": "self.version", @@ -22,7 +23,8 @@ "neos/utility-mediatypes": "*", "neos/error-messages": "*", "doctrine/common": "^2.7 || ^3.0", - "doctrine/orm": "^2.6" + "doctrine/orm": "^2.6", + "enshrined/svg-sanitize": "^0.16.0" }, "autoload": { "psr-4": { diff --git a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php index c5ade354882..d0aeeae4dc3 100644 --- a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php +++ b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php @@ -606,8 +606,8 @@ protected function renderContentChanges(NodeInterface $changedNode) 'diff' => $diffArray ]; } - // The && in belows condition is on purpose as creating a thumbnail for comparison only works if actually - // BOTH are ImageInterface (or NULL). + // The && in belows condition is on purpose as creating a thumbnail for comparison only works if actually + // BOTH are ImageInterface (or NULL). } elseif ( ($originalPropertyValue instanceof ImageInterface || $originalPropertyValue === null) && ($changedPropertyValue instanceof ImageInterface || $changedPropertyValue === null) diff --git a/composer.json b/composer.json index a4447f871d6..a0cabf5c43d 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "neos/party": "*", "neos/fusion-form": "^1.0 || ^2.0", "neos/form": "*", - "neos/kickstarter": "~8.0.0" + "neos/kickstarter": "~8.0.0", + "enshrined/svg-sanitize": "^0.16.0" }, "replace": { "typo3/typo3cr": "self.version",