Skip to content

Commit

Permalink
Merged branch '4.5' into 4.6
Browse files Browse the repository at this point in the history
  • Loading branch information
alongosz committed Mar 20, 2024
2 parents b934a7e + 862a2b4 commit 51fb879
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 32 deletions.
2 changes: 1 addition & 1 deletion phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10652,7 +10652,7 @@ parameters:

-
message: "#^Access to an undefined property Ibexa\\\\Core\\\\FieldType\\\\Value\\:\\:\\$fileName\\.$#"
count: 2
count: 1
path: src/lib/FieldType/Validator/FileExtensionBlackListValidator.php

-
Expand Down
32 changes: 23 additions & 9 deletions src/lib/FieldType/BinaryBase/BinaryBaseStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use Ibexa\Contracts\Core\IO\MimeTypeDetector;
use Ibexa\Contracts\Core\Persistence\Content\Field;
use Ibexa\Contracts\Core\Persistence\Content\VersionInfo;
use Ibexa\Core\Base\Exceptions\ContentFieldValidationException;
use Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator;
use Ibexa\Core\IO\IOServiceInterface;

/**
Expand All @@ -39,24 +41,21 @@ class BinaryBaseStorage extends GatewayBasedStorage
/** @var \Ibexa\Core\FieldType\BinaryBase\BinaryBaseStorage\Gateway */
protected $gateway;

/**
* Construct from gateways.
*
* @param \Ibexa\Contracts\Core\FieldType\StorageGatewayInterface $gateway
* @param \Ibexa\Core\IO\IOServiceInterface $ioService
* @param \Ibexa\Contracts\Core\FieldType\BinaryBase\PathGenerator $pathGenerator
* @param \Ibexa\Contracts\Core\IO\MimeTypeDetector $mimeTypeDetector
*/
/** @var \Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator */
protected $fileExtensionBlackListValidator;

public function __construct(
StorageGatewayInterface $gateway,
IOServiceInterface $ioService,
PathGenerator $pathGenerator,
MimeTypeDetector $mimeTypeDetector
MimeTypeDetector $mimeTypeDetector,
FileExtensionBlackListValidator $fileExtensionBlackListValidator
) {
parent::__construct($gateway);
$this->ioService = $ioService;
$this->pathGenerator = $pathGenerator;
$this->mimeTypeDetector = $mimeTypeDetector;
$this->fileExtensionBlackListValidator = $fileExtensionBlackListValidator;
}

/**
Expand All @@ -67,6 +66,10 @@ public function setDownloadUrlGenerator(PathGenerator $downloadUrlGenerator)
$this->downloadUrlGenerator = $downloadUrlGenerator;
}

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
*/
public function storeFieldData(VersionInfo $versionInfo, Field $field, array $context)
{
if ($field->value->externalData === null) {
Expand All @@ -76,6 +79,17 @@ public function storeFieldData(VersionInfo $versionInfo, Field $field, array $co
}

if (isset($field->value->externalData['inputUri'])) {
$this->fileExtensionBlackListValidator->validateFileExtension($field->value->externalData['fileName']);
if (!empty($errors = $this->fileExtensionBlackListValidator->getErrors())) {
$preparedErrors = [];
$preparedErrors[$field->fieldDefinitionId][$field->languageCode] = $errors;

throw ContentFieldValidationException::createNewWithMultiline(
$preparedErrors,
$versionInfo->contentInfo->name
);
}

$field->value->externalData['mimeType'] = $this->mimeTypeDetector->getFromPath($field->value->externalData['inputUri']);
$createStruct = $this->ioService->newBinaryCreateStructFromLocalFile($field->value->externalData['inputUri']);
$createStruct->id = $this->pathGenerator->getStoragePathForField($field, $versionInfo);
Expand Down
25 changes: 24 additions & 1 deletion src/lib/FieldType/Image/ImageStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
use Ibexa\Contracts\Core\FieldType\StorageGatewayInterface;
use Ibexa\Contracts\Core\Persistence\Content\Field;
use Ibexa\Contracts\Core\Persistence\Content\VersionInfo;
use Ibexa\Core\Base\Exceptions\ContentFieldValidationException;
use Ibexa\Core\Base\Exceptions\InvalidArgumentException;
use Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator;
use Ibexa\Core\IO\FilePathNormalizerInterface;
use Ibexa\Core\IO\IOServiceInterface;
use Ibexa\Core\IO\MetadataHandler;
Expand Down Expand Up @@ -38,22 +40,32 @@ class ImageStorage extends GatewayBasedStorage
/** @var \Ibexa\Core\IO\FilePathNormalizerInterface */
protected $filePathNormalizer;

/** @var \Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator */
protected $fileExtensionBlackListValidator;

public function __construct(
StorageGatewayInterface $gateway,
IOServiceInterface $ioService,
PathGenerator $pathGenerator,
MetadataHandler $imageSizeMetadataHandler,
AliasCleanerInterface $aliasCleaner,
FilePathNormalizerInterface $filePathNormalizer
FilePathNormalizerInterface $filePathNormalizer,
FileExtensionBlackListValidator $fileExtensionBlackListValidator
) {
parent::__construct($gateway);
$this->ioService = $ioService;
$this->pathGenerator = $pathGenerator;
$this->imageSizeMetadataHandler = $imageSizeMetadataHandler;
$this->aliasCleaner = $aliasCleaner;
$this->filePathNormalizer = $filePathNormalizer;
$this->fileExtensionBlackListValidator = $fileExtensionBlackListValidator;
}

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
*/
public function storeFieldData(VersionInfo $versionInfo, Field $field, array $context)
{
$contentMetaData = [
Expand All @@ -64,6 +76,17 @@ public function storeFieldData(VersionInfo $versionInfo, Field $field, array $co

// new image
if (isset($field->value->externalData)) {
$this->fileExtensionBlackListValidator->validateFileExtension($field->value->externalData['fileName']);
if (!empty($errors = $this->fileExtensionBlackListValidator->getErrors())) {
$preparedErrors = [];
$preparedErrors[$field->fieldDefinitionId][$field->languageCode] = $errors;

throw ContentFieldValidationException::createNewWithMultiline(
$preparedErrors,
$versionInfo->contentInfo->name
);
}

$targetPath = sprintf(
'%s/%s',
$this->pathGenerator->getStoragePathForField(
Expand Down
29 changes: 23 additions & 6 deletions src/lib/FieldType/Validator/FileExtensionBlackListValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,41 @@ public function validateConstraints($constraints)
* {@inheritdoc}
*/
public function validate(BaseValue $value, ?FieldDefinition $fieldDefinition = null)
{
$this->errors = [];

$this->validateFileExtension($value->fileName);

return empty($this->errors);
}

public function validateFileExtension(string $fileName): void
{
if (
pathinfo($value->fileName, PATHINFO_BASENAME) !== $value->fileName ||
in_array(strtolower(pathinfo($value->fileName, PATHINFO_EXTENSION)), $this->constraints['extensionsBlackList'], true)
pathinfo($fileName, PATHINFO_BASENAME) !== $fileName
|| in_array(
strtolower(pathinfo($fileName, PATHINFO_EXTENSION)),
$this->constraints['extensionsBlackList'],
true
)
) {
$this->errors[] = new ValidationError(
'A valid file is required. Following file extensions are on the blacklist: %extensionsBlackList%',
'A valid file is required. The following file extensions are not allowed: %extensionsBlackList%',
null,
[
'%extensionsBlackList%' => implode(', ', $this->constraints['extensionsBlackList']),
],
'fileExtensionBlackList'
);

return false;
}
}

return true;
/**
* @return array<\Ibexa\Contracts\Core\FieldType\ValidationError>
*/
public function getErrors(): array
{
return $this->errors;
}
}

Expand Down
19 changes: 11 additions & 8 deletions src/lib/Resources/settings/fieldtype_external_storages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ services:
Ibexa\Core\FieldType\BinaryFile\BinaryFileStorage:
class: Ibexa\Core\FieldType\BinaryFile\BinaryFileStorage
arguments:
- '@Ibexa\Core\FieldType\BinaryFile\BinaryFileStorage\Gateway\DoctrineStorage'
- '@ibexa.field_type.ezbinaryfile.io_service'
- '@Ibexa\Core\FieldType\BinaryBase\PathGenerator\LegacyPathGenerator'
- '@ibexa.core.io.mimeTypeDetector'
$gateway: '@Ibexa\Core\FieldType\BinaryFile\BinaryFileStorage\Gateway\DoctrineStorage'
$ioService: '@ibexa.field_type.ezbinaryfile.io_service'
$pathGenerator: '@Ibexa\Core\FieldType\BinaryBase\PathGenerator\LegacyPathGenerator'
$mimeTypeDetector: '@ibexa.core.io.mimeTypeDetector'
$fileExtensionBlackListValidator: '@Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator'
tags:
- {name: ibexa.field_type.storage.external.handler, alias: ezbinaryfile}

Expand All @@ -18,6 +19,7 @@ services:
$imageSizeMetadataHandler: '@Ibexa\Core\IO\MetadataHandler\ImageSize'
$aliasCleaner: '@Ibexa\Core\FieldType\Image\AliasCleanerInterface'
$filePathNormalizer: '@Ibexa\Core\IO\FilePathNormalizerInterface'
$fileExtensionBlackListValidator: '@Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator'
tags:
- {name: ibexa.field_type.storage.external.handler, alias: ezimage}

Expand All @@ -30,10 +32,11 @@ services:
Ibexa\Core\FieldType\Media\MediaStorage:
class: Ibexa\Core\FieldType\Media\MediaStorage
arguments:
- '@Ibexa\Core\FieldType\Media\MediaStorage\Gateway\DoctrineStorage'
- '@ibexa.field_type.ezbinaryfile.io_service'
- '@Ibexa\Core\FieldType\BinaryBase\PathGenerator\LegacyPathGenerator'
- '@ibexa.core.io.mimeTypeDetector'
$gateway: '@Ibexa\Core\FieldType\Media\MediaStorage\Gateway\DoctrineStorage'
$ioService: '@ibexa.field_type.ezbinaryfile.io_service'
$pathGenerator: '@Ibexa\Core\FieldType\BinaryBase\PathGenerator\LegacyPathGenerator'
$mimeTypeDetector: '@ibexa.core.io.mimeTypeDetector'
$fileExtensionBlackListValidator: '@Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator'
tags:
- {name: ibexa.field_type.storage.external.handler, alias: ezmedia}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Ibexa\Core\FieldType\BinaryBase\BinaryBaseStorage;
use Ibexa\Core\FieldType\BinaryBase\BinaryBaseStorage\Gateway;
use Ibexa\Core\FieldType\BinaryFile\BinaryFileStorage\Gateway\DoctrineStorage;
use Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator;
use Ibexa\Core\IO\IOServiceInterface;
use Ibexa\Core\IO\Values\BinaryFile;
use Ibexa\Core\IO\Values\BinaryFileCreateStruct;
Expand All @@ -36,13 +37,19 @@ class BinaryBaseStorageTest extends BaseCoreFieldTypeIntegrationTest
/** @var \Ibexa\Core\FieldType\BinaryBase\BinaryBaseStorage|\PHPUnit\Framework\MockObject\MockObject */
protected $storage;

/** @var \Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator&\PHPUnit\Framework\MockObject\MockObject */
protected $fileExtensionBlackListValidatorMock;

protected function setUp(): void
{
parent::setUp();

$this->gateway = $this->getStorageGateway();
$this->pathGeneratorMock = $this->createMock(PathGenerator::class);
$this->ioServiceMock = $this->createMock(IOServiceInterface::class);
$this->fileExtensionBlackListValidatorMock = $this->createMock(
FileExtensionBlackListValidator::class
);
$this->storage = $this->getMockBuilder(BinaryBaseStorage::class)
->onlyMethods([])
->setConstructorArgs(
Expand All @@ -51,6 +58,7 @@ protected function setUp(): void
$this->ioServiceMock,
$this->pathGeneratorMock,
$this->createMock(MimeTypeDetector::class),
$this->fileExtensionBlackListValidatorMock,
]
)
->getMock();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Ibexa\Core\FieldType\Image\ImageStorage;
use Ibexa\Core\FieldType\Image\ImageStorage\Gateway\DoctrineStorage;
use Ibexa\Core\FieldType\Image\PathGenerator;
use Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator;
use Ibexa\Core\IO\FilePathNormalizerInterface;
use Ibexa\Core\IO\IOServiceInterface;
use Ibexa\Core\IO\MetadataHandler;
Expand Down Expand Up @@ -50,6 +51,9 @@ final class ImageStorageTest extends BaseCoreFieldTypeIntegrationTest
/** @var \Ibexa\Core\FieldType\Image\ImageStorage */
private $storage;

/** @var \Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator&\PHPUnit\Framework\MockObject\MockObject */
private $fileExtensionBlackListValidator;

protected function setUp(): void
{
parent::setUp();
Expand All @@ -61,13 +65,15 @@ protected function setUp(): void
$this->aliasCleaner = $this->createMock(AliasCleanerInterface::class);
$this->filePathNormalizer = $this->createMock(FilePathNormalizerInterface::class);
$this->ioService = $this->createMock(IOServiceInterface::class);
$this->fileExtensionBlackListValidator = $this->createMock(FileExtensionBlackListValidator::class);
$this->storage = new ImageStorage(
$this->gateway,
$this->ioService,
$this->pathGenerator,
$this->imageSizeMetadataHandler,
$this->aliasCleaner,
$this->filePathNormalizer,
$this->fileExtensionBlackListValidator
);
}

Expand Down
4 changes: 2 additions & 2 deletions tests/lib/FieldType/BinaryFileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ public function provideInvalidDataForValidate()
),
[
new ValidationError(
'A valid file is required. Following file extensions are on the blacklist: %extensionsBlackList%',
'A valid file is required. The following file extensions are not allowed: %extensionsBlackList%',
null,
['%extensionsBlackList%' => implode(', ', $this->blackListedExtensions)],
'fileExtensionBlackList'
Expand Down Expand Up @@ -623,7 +623,7 @@ public function provideInvalidDataForValidate()
),
[
new ValidationError(
'A valid file is required. Following file extensions are on the blacklist: %extensionsBlackList%',
'A valid file is required. The following file extensions are not allowed: %extensionsBlackList%',
null,
['%extensionsBlackList%' => implode(', ', $this->blackListedExtensions)],
'fileExtensionBlackList'
Expand Down
8 changes: 4 additions & 4 deletions tests/lib/FieldType/ImageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ public function provideInvalidDataForValidate()
),
[
new ValidationError(
'A valid file is required. Following file extensions are on the blacklist: %extensionsBlackList%',
'A valid file is required. The following file extensions are not allowed: %extensionsBlackList%',
null,
['%extensionsBlackList%' => implode(', ', $this->blackListedExtensions)],
'fileExtensionBlackList'
Expand Down Expand Up @@ -738,7 +738,7 @@ public function provideInvalidDataForValidate()
),
[
new ValidationError(
'A valid file is required. Following file extensions are on the blacklist: %extensionsBlackList%',
'A valid file is required. The following file extensions are not allowed: %extensionsBlackList%',
null,
['%extensionsBlackList%' => implode(', ', $this->blackListedExtensions)],
'fileExtensionBlackList'
Expand Down Expand Up @@ -773,7 +773,7 @@ public function provideInvalidDataForValidate()
),
[
new ValidationError(
'A valid file is required. Following file extensions are on the blacklist: %extensionsBlackList%',
'A valid file is required. The following file extensions are not allowed: %extensionsBlackList%',
null,
['%extensionsBlackList%' => implode(', ', $this->blackListedExtensions)],
'fileExtensionBlackList'
Expand Down Expand Up @@ -805,7 +805,7 @@ public function provideInvalidDataForValidate()
),
[
new ValidationError(
'A valid file is required. Following file extensions are on the blacklist: %extensionsBlackList%',
'A valid file is required. The following file extensions are not allowed: %extensionsBlackList%',
null,
['%extensionsBlackList%' => implode(', ', $this->blackListedExtensions)],
'fileExtensionBlackList'
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/FieldType/MediaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ public function provideInvalidDataForValidate()
),
[
new ValidationError(
'A valid file is required. Following file extensions are on the blacklist: %extensionsBlackList%',
'A valid file is required. The following file extensions are not allowed: %extensionsBlackList%',
null,
['%extensionsBlackList%' => implode(', ', $this->blackListedExtensions)],
'fileExtensionBlackList'
Expand Down

0 comments on commit 51fb879

Please sign in to comment.