|
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ExampleVendor\ExampleVendorNamespace\EventListener;
|
|
|
|
use Psr\Log\InvalidArgumentException;
|
|
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
|
use TYPO3\CMS\Core\Exception;
|
|
use TYPO3\CMS\Core\Messaging\AbstractMessage;
|
|
use TYPO3\CMS\Core\Messaging\FlashMessage;
|
|
use TYPO3\CMS\Core\Messaging\FlashMessageService;
|
|
use \TYPO3\CMS\Core\Resource\Event\BeforeFileAddedEvent;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
|
|
class StorageExtensionBlocker
|
|
{
|
|
/**
|
|
* @param BeforeFileAddedEvent $event
|
|
* @throws Exception
|
|
* @throws InvalidArgumentException
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
public function __invoke(BeforeFileAddedEvent $event): void
|
|
{
|
|
$storageId = $event->getStorage()->getUid();
|
|
$pageTsConfig = BackendUtility::getPagesTSconfig(1);
|
|
$userTsConfig = $GLOBALS['BE_USER']->getTSConfig();
|
|
$permissions = $pageTsConfig['permissions.']['file.']['storage.'][$storageId.'.']['allowedExtensions'] ?? null;
|
|
$permissions = $userTsConfig['permissions.']['file.']['storage.'][$storageId.'.']['allowedExtensions'] ?? $permissions;
|
|
|
|
$fileName = $event->getFileName();
|
|
|
|
if ($permissions === null) {
|
|
return;
|
|
}
|
|
|
|
if ($this->isValid($fileName, $permissions)) {
|
|
return;
|
|
}
|
|
|
|
$this->addFlashMessageAndThrowError($event, $pageTsConfig, $storageId, $permissions, $fileName);
|
|
}
|
|
|
|
/**
|
|
* Verifies the input filename against the 'allowedExtensions'
|
|
* Page TSconfig permissions.file.storage.[storageUid].allowedExtensions
|
|
*
|
|
* Filenames are not allowed to contain control characters. Therefore, we
|
|
* always filter on [[:cntrl:]].
|
|
*
|
|
* @param string $fileName File path to evaluate
|
|
* @return bool Returns TRUE if the file name is OK.
|
|
*/
|
|
public function isValid(string $fileName, string $fileAllowPattern): bool
|
|
{
|
|
$pattern = '/[[:cntrl:]]/';
|
|
if ($fileName !== '' && $fileAllowPattern !== '') {
|
|
$pattern = '/(?:[[:cntrl:]]|\\.(' . $fileAllowPattern . ')(\\..*)?$)/iu';
|
|
}
|
|
return preg_match($pattern, $fileName) === 1;
|
|
}
|
|
|
|
/**
|
|
* @param BeforeFileAddedEvent $event
|
|
* @param array|null $pageTsConfig
|
|
* @param int $storageId
|
|
* @param mixed $permissions
|
|
* @param string $fileName
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
private function addFlashMessageAndThrowError(BeforeFileAddedEvent $event, ?array $pageTsConfig, int $storageId, mixed $permissions, string $fileName): void
|
|
{
|
|
$label = '%s
|
|
Extension of file %s is not allowed!
|
|
Allowed types for this drive: %s.';
|
|
$flashMessage = GeneralUtility::makeInstance(
|
|
FlashMessage::class,
|
|
vsprintf($label, [
|
|
$pageTsConfig['permissions.']['file.']['storage.'][$storageId.'.']['allowedExtensionsMsg'] ?? null,
|
|
$event->getFileName(),
|
|
str_replace('|', ', ', $permissions),
|
|
]),
|
|
'File extension not allowed',
|
|
AbstractMessage::ERROR,
|
|
true
|
|
);
|
|
$this->addFlashMessage($flashMessage);
|
|
|
|
$targetFolder = $event->getTargetFolder();
|
|
$basePath = $event->getStorage()->getConfiguration()['basePath'];
|
|
$fullTargetLocation = $basePath.$targetFolder->getIdentifier();
|
|
|
|
throw new \InvalidArgumentException('File extension not permitted: '.$fullTargetLocation.$fileName, 1325777289);
|
|
}
|
|
|
|
/**
|
|
* Add flash message to message queue
|
|
*
|
|
* @param FlashMessage $flashMessage
|
|
* @throws \InvalidArgumentException
|
|
* @throws Exception
|
|
*/
|
|
protected function addFlashMessage(FlashMessage $flashMessage): void
|
|
{
|
|
$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
|
|
$defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
|
|
$defaultFlashMessageQueue->enqueue($flashMessage);
|
|
}
|
|
}
|