Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IBX-6856: Added mime types limitation for ezimage field type #300

Merged
65 changes: 0 additions & 65 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10745,11 +10745,6 @@ parameters:
count: 1
path: src/lib/FieldType/Validator/FloatValueValidator.php

-
message: "#^Method Ibexa\\\\Core\\\\FieldType\\\\Validator\\\\ImageValidator\\:\\:innerValidate\\(\\) has no return type specified\\.$#"
count: 1
path: src/lib/FieldType/Validator/ImageValidator.php

-
message: "#^Method Ibexa\\\\Core\\\\FieldType\\\\Validator\\\\ImageValidator\\:\\:innerValidate\\(\\) has parameter \\$filePath with no type specified\\.$#"
count: 1
Expand Down Expand Up @@ -30605,21 +30600,6 @@ parameters:
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:assertCopiedFieldDataLoadedCorrectly\\(\\) has no return type specified\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:assertUpdatedFieldDataLoadedCorrect\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:assertUpdatedFieldDataLoadedCorrect\\(\\) should return array but return statement is missing\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:getAdditionallyIndexedFieldData\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
Expand All @@ -30630,31 +30610,11 @@ parameters:
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:getSettingsSchema\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:getStoragePrefix\\(\\) has no return type specified\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:getValidUpdateFieldData\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:getValidUpdateFieldData\\(\\) should return array but returns Ibexa\\\\Core\\\\FieldType\\\\Image\\\\Value\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:getValidatorSchema\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:provideFromHashData\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
Expand All @@ -30675,36 +30635,11 @@ parameters:
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:providerForTestIsEmptyValue\\(\\) has no return type specified\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:providerForTestIsNotEmptyValue\\(\\) has no return type specified\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:publishNewImage\\(\\) has parameter \\$parentLocationIDs with no value type specified in iterable type array\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:testInherentCopyForNewLanguage\\(\\) has no return type specified\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:testUpdatingImageMetadataOnlyWorks\\(\\) has no return type specified\\.$#"
count: 1
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Parameter \\#2 \\$newImageValue of method Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:updateImage\\(\\) expects Ibexa\\\\Core\\\\FieldType\\\\Image\\\\Value, array given\\.$#"
count: 2
path: tests/integration/Core/Repository/FieldType/ImageIntegrationTest.php

-
message: "#^Property Ibexa\\\\Tests\\\\Integration\\\\Core\\\\Repository\\\\FieldType\\\\ImageIntegrationTest\\:\\:\\$loadedImagePath has no type specified\\.$#"
count: 1
Expand Down
65 changes: 61 additions & 4 deletions src/lib/FieldType/Image/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,37 @@ class Type extends FieldType implements TranslationContainerInterface
],
];

/**
* @var array{
* mimeTypes: array{
* type: string,
* default: array{},
* }
* }
*/
protected $settingsSchema = [
konradoboza marked this conversation as resolved.
Show resolved Hide resolved
'mimeTypes' => [
'type' => 'choice',
'default' => [],
],
];

/** @var \Ibexa\Core\FieldType\Validator[] */
private $validators;

/** @var array<string> */
private array $mimeTypes;

/**
* @param \Ibexa\Core\FieldType\Validator[] $validators
* @param array<\Ibexa\Core\FieldType\Validator> $validators
* @param array<string> $mimeTypes
*/
public function __construct(array $validators)
{
public function __construct(
array $validators,
array $mimeTypes = []
) {
$this->validators = $validators;
$this->mimeTypes = $mimeTypes;
}

/**
Expand Down Expand Up @@ -166,7 +188,7 @@ public function validate(FieldDefinition $fieldDefinition, SPIValue $fieldValue)
}

foreach ($this->validators as $externalValidator) {
if (!$externalValidator->validate($fieldValue)) {
if (!$externalValidator->validate($fieldValue, $fieldDefinition)) {
$errors = array_merge($errors, $externalValidator->getMessage());
}
}
Expand Down Expand Up @@ -207,6 +229,41 @@ public function validate(FieldDefinition $fieldDefinition, SPIValue $fieldValue)
return $errors;
}

public function validateFieldSettings($fieldSettings): array
{
$validationErrors = [];

foreach ($fieldSettings as $name => $value) {
if (!isset($this->settingsSchema[$name])) {
$validationErrors[] = new ValidationError(
"Setting '%setting%' is unknown",
null,
[
'%setting%' => $name,
],
"[$name]"
);
}

if (
$name === 'mimeTypes'
&& !empty($this->mimeTypes)
&& !empty(array_diff($value, $this->mimeTypes))
) {
$validationErrors[] = new ValidationError(
"Setting '%setting%' contains unsupported mime types",
null,
[
'%setting%' => $name,
],
"[$name]"
);
}
}

return $validationErrors;
}

/**
* Validates the validatorConfiguration of a FieldDefinitionCreateStruct or FieldDefinitionUpdateStruct.
*
Expand Down
3 changes: 2 additions & 1 deletion src/lib/FieldType/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
namespace Ibexa\Core\FieldType;

use Ibexa\Contracts\Core\Repository\Exceptions\PropertyNotFoundException as PropertyNotFound;
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;

/**
* Base field type validator validator.
Expand Down Expand Up @@ -98,7 +99,7 @@ abstract public function validateConstraints($constraints);
*
* @return bool
*/
abstract public function validate(Value $value);
abstract public function validate(Value $value, ?FieldDefinition $fieldDefinition = null);
Copy link
Member

@alongosz alongosz Dec 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

This is not an internal class, but it hasn't been documented as an SPI either, so I would just add a note in the upgrade/release notes that this method got an extra parameter (If it were an SPI it would be a breaking change).


/**
* Returns array of messages on performed validations.
Expand Down
3 changes: 2 additions & 1 deletion src/lib/FieldType/Validator/EmailAddressValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ibexa\Core\FieldType\Validator;

use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Core\FieldType\ValidationError;
use Ibexa\Core\FieldType\Validator;
use Ibexa\Core\FieldType\Value as BaseValue;
Expand Down Expand Up @@ -84,7 +85,7 @@ public function validateConstraints($constraints)
*
* @return bool
*/
public function validate(BaseValue $value)
public function validate(BaseValue $value, ?FieldDefinition $fieldDefinition = null)
{
$pattern = '/^((\"[^\"\f\n\r\t\v\b]+\")|([A-Za-z0-9_\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+(\.[A-Za-z0-9_\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]{2,}))$/';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ibexa\Core\FieldType\Validator;

use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
use Ibexa\Core\FieldType\ValidationError;
use Ibexa\Core\FieldType\Validator;
Expand Down Expand Up @@ -45,7 +46,7 @@ public function validateConstraints($constraints)
/**
* {@inheritdoc}
*/
public function validate(BaseValue $value)
public function validate(BaseValue $value, ?FieldDefinition $fieldDefinition = null)
{
if (
pathinfo($value->fileName, PATHINFO_BASENAME) !== $value->fileName ||
Expand Down
3 changes: 2 additions & 1 deletion src/lib/FieldType/Validator/FileSizeValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ibexa\Core\FieldType\Validator;

use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Core\FieldType\ValidationError;
use Ibexa\Core\FieldType\Validator;
use Ibexa\Core\FieldType\Value as BaseValue;
Expand Down Expand Up @@ -66,7 +67,7 @@ public function validateConstraints($constraints)
*
* @return bool
*/
public function validate(BaseValue $value)
public function validate(BaseValue $value, ?FieldDefinition $fieldDefinition = null)
{
$isValid = true;

Expand Down
3 changes: 2 additions & 1 deletion src/lib/FieldType/Validator/FloatValueValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ibexa\Core\FieldType\Validator;

use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Core\FieldType\ValidationError;
use Ibexa\Core\FieldType\Validator;
use Ibexa\Core\FieldType\Value as BaseValue;
Expand Down Expand Up @@ -82,7 +83,7 @@ public function validateConstraints($constraints)
*
* @return bool
*/
public function validate(BaseValue $value)
public function validate(BaseValue $value, ?FieldDefinition $fieldDefinition = null)
{
$isValid = true;

Expand Down
42 changes: 36 additions & 6 deletions src/lib/FieldType/Validator/ImageValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ibexa\Core\FieldType\Validator;

use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Core\FieldType\ValidationError;
use Ibexa\Core\FieldType\Validator;
use Ibexa\Core\FieldType\Value;
Expand All @@ -15,34 +16,43 @@ class ImageValidator extends Validator
/**
* {@inheritdoc}
*/
public function validateConstraints($constraints)
public function validateConstraints($constraints, ?FieldDefinition $fieldDefinition = null)
{
return [];
}

/**
* {@inheritdoc}
*/
public function validate(Value $value)
public function validate(Value $value, ?FieldDefinition $fieldDefinition = null)
{
$mimeTypes = [];
if (null !== $fieldDefinition) {
$mimeTypes = $fieldDefinition->getFieldSettings()['mimeTypes'] ?? [];
}

$isValid = true;
if (isset($value->inputUri) && !$this->innerValidate($value->inputUri)) {
if (isset($value->inputUri) && !$this->innerValidate($value->inputUri, $mimeTypes)) {
$isValid = false;
}

// BC: Check if file is a valid image if the value of 'id' matches a local file
if (isset($value->id) && file_exists($value->id) && !$this->innerValidate($value->id)) {
if (isset($value->id) && file_exists($value->id) && !$this->innerValidate($value->id, $mimeTypes)) {
$isValid = false;
}

return $isValid;
}

private function innerValidate($filePath)
/**
* @param array<string> $mimeTypes
*/
private function innerValidate($filePath, array $mimeTypes): bool
{
// silence `getimagesize` error as extension-wise valid image files might produce it anyway
// note that file extension checking is done using other validation which should be called before this one
if (!@getimagesize($filePath)) {
$imageData = @getimagesize($filePath);
if (false === $imageData) {
$this->errors[] = new ValidationError(
'A valid image file is required.',
null,
Expand All @@ -53,6 +63,26 @@ private function innerValidate($filePath)
return false;
}

// If array with mime types is empty, it means that all mime types are allowed
if (empty($mimeTypes)) {
return true;
}

$mimeType = $imageData['mime'];
if (!in_array($mimeType, $mimeTypes, true)) {
$this->errors[] = new ValidationError(
'The mime type of the file is invalid (%mimeType%). Allowed mime types are %mimeTypes%.',
null,
[
'%mimeType%' => $mimeType,
'%mimeTypes%' => implode(', ', $mimeTypes),
],
'id'
);

return false;
}

return true;
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/lib/FieldType/Validator/IntegerValueValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ibexa\Core\FieldType\Validator;

use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Core\FieldType\ValidationError;
use Ibexa\Core\FieldType\Validator;
use Ibexa\Core\FieldType\Value as BaseValue;
Expand Down Expand Up @@ -85,7 +86,7 @@ public function validateConstraints($constraints)
*
* @return bool
*/
public function validate(BaseValue $value)
public function validate(BaseValue $value, ?FieldDefinition $fieldDefinition = null)
{
$isValid = true;

Expand Down
3 changes: 2 additions & 1 deletion src/lib/FieldType/Validator/StringLengthValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ibexa\Core\FieldType\Validator;

use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Core\FieldType\ValidationError;
use Ibexa\Core\FieldType\Validator;
use Ibexa\Core\FieldType\Value as BaseValue;
Expand Down Expand Up @@ -104,7 +105,7 @@ protected function validateConstraintsOrder($constraints)
*
* @return bool
*/
public function validate(BaseValue $value)
public function validate(BaseValue $value, ?FieldDefinition $fieldDefinition = null)
{
$isValid = true;

Expand Down
Loading
Loading