Validate regex in string pattern and object patternProperties

[MAILPOET-4195]
This commit is contained in:
Jan Jakes
2022-03-25 10:52:55 +01:00
committed by Veljko V
parent 2bbc086121
commit 2668af08b7
5 changed files with 49 additions and 6 deletions

View File

@@ -87,4 +87,12 @@ abstract class Schema {
protected function getReservedKeywords(): array {
return rest_get_allowed_schema_keywords();
}
protected function validatePattern(string $pattern): void {
$escaped = str_replace('#', '\\#', $pattern);
$regex = "#$escaped#u";
if (@preg_match($regex, '') === false) {
throw new InvalidStateException("Invalid regular expression '$regex'");
}
}
}

View File

@@ -35,12 +35,12 @@ class ObjectSchema extends Schema {
* @param array<string, Schema> $properties
*/
public function patternProperties(array $properties): self {
return $this->updateSchemaProperty('patternProperties', array_map(
function (Schema $property) {
return $property->toArray();
},
$properties
));
$patternProperties = [];
foreach ($properties as $key => $value) {
$this->validatePattern($key);
$patternProperties[$key] = $value->toArray();
}
return $this->updateSchemaProperty('patternProperties', $patternProperties);
}
public function minProperties(int $value): self {

View File

@@ -23,6 +23,7 @@ class StringSchema extends Schema {
* See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#pattern
*/
public function pattern(string $pattern): self {
$this->validatePattern($pattern);
return $this->updateSchemaProperty('pattern', $pattern);
}

View File

@@ -2,6 +2,7 @@
namespace MailPoet\Validator\Schema;
use MailPoet\InvalidStateException;
use MailPoet\Validator\Schema;
use MailPoetUnitTest;
@@ -104,6 +105,11 @@ class ObjectSchemaTest extends MailPoetUnitTest {
'{"type":"object","patternProperties":{"^number-[0-9]+":{"type":"number"},"^string-[0-9]+":{"type":"string"}}}',
$object->toString()
);
$this->assertInvalidPatternProperty(['\\' => $this->getNumberSchemaMock()], "Invalid regular expression '#\\#u'");
$this->assertInvalidPatternProperty(['\\#' => $this->getStringSchemaMock()], "Invalid regular expression '#\\\\##u'");
$this->assertInvalidPatternProperty(['[' => $this->getNumberSchemaMock()], "Invalid regular expression '#[#u'");
$this->assertInvalidPatternProperty(['[0-9' => $this->getStringSchemaMock()], "Invalid regular expression '#[0-9#u'");
}
public function testMinProperties(): void {
@@ -174,4 +180,15 @@ class ObjectSchemaTest extends MailPoetUnitTest {
protected $schema = ['type' => 'string'];
};
}
private function assertInvalidPatternProperty(array $properties, string $message): void {
try {
(new ObjectSchema())->patternProperties($properties);
} catch (InvalidStateException $e) {
$this->assertSame($message, $e->getMessage());
return;
}
$class = InvalidStateException::class;
$this->fail("Exception '$class' with message '$message' was not thrown.");
}
}

View File

@@ -2,6 +2,7 @@
namespace MailPoet\Validator\Schema;
use MailPoet\InvalidStateException;
use MailPoetUnitTest;
class StringSchemaTest extends MailPoetUnitTest {
@@ -27,6 +28,11 @@ class StringSchemaTest extends MailPoetUnitTest {
$string = (new StringSchema())->pattern('[0-9]+');
$this->assertSame(['type' => 'string', 'pattern' => '[0-9]+'], $string->toArray());
$this->assertSame('{"type":"string","pattern":"[0-9]+"}', $string->toString());
$this->assertInvalidPattern('\\', "Invalid regular expression '#\\#u'");
$this->assertInvalidPattern('\\#', "Invalid regular expression '#\\\\##u'");
$this->assertInvalidPattern('[', "Invalid regular expression '#[#u'");
$this->assertInvalidPattern('[0-9', "Invalid regular expression '#[0-9#u'");
}
public function testFormat(): void {
@@ -88,4 +94,15 @@ class StringSchemaTest extends MailPoetUnitTest {
$this->assertNotSame($string->formatUri(), $string);
$this->assertNotSame($string->formatUuid(), $string);
}
private function assertInvalidPattern(string $pattern, string $message): void {
try {
(new StringSchema())->pattern($pattern);
} catch (InvalidStateException $e) {
$this->assertSame($message, $e->getMessage());
return;
}
$class = InvalidStateException::class;
$this->fail("Exception '$class' with message '$message' was not thrown.");
}
}