diff --git a/mailpoet/lib/Validator/Schema.php b/mailpoet/lib/Validator/Schema.php index e2407cb4b9..eb1dff3fa6 100644 --- a/mailpoet/lib/Validator/Schema.php +++ b/mailpoet/lib/Validator/Schema.php @@ -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'"); + } + } } diff --git a/mailpoet/lib/Validator/Schema/ObjectSchema.php b/mailpoet/lib/Validator/Schema/ObjectSchema.php index 8863b417a0..dd8cab7f7f 100644 --- a/mailpoet/lib/Validator/Schema/ObjectSchema.php +++ b/mailpoet/lib/Validator/Schema/ObjectSchema.php @@ -35,12 +35,12 @@ class ObjectSchema extends Schema { * @param array $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 { diff --git a/mailpoet/lib/Validator/Schema/StringSchema.php b/mailpoet/lib/Validator/Schema/StringSchema.php index a661a89184..172eb66e75 100644 --- a/mailpoet/lib/Validator/Schema/StringSchema.php +++ b/mailpoet/lib/Validator/Schema/StringSchema.php @@ -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); } diff --git a/mailpoet/tests/unit/Validator/Schema/ObjectSchemaTest.php b/mailpoet/tests/unit/Validator/Schema/ObjectSchemaTest.php index 7ebdf73491..85fb3f35e8 100644 --- a/mailpoet/tests/unit/Validator/Schema/ObjectSchemaTest.php +++ b/mailpoet/tests/unit/Validator/Schema/ObjectSchemaTest.php @@ -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."); + } } diff --git a/mailpoet/tests/unit/Validator/Schema/StringSchemaTest.php b/mailpoet/tests/unit/Validator/Schema/StringSchemaTest.php index 50f838c615..3ee066e894 100644 --- a/mailpoet/tests/unit/Validator/Schema/StringSchemaTest.php +++ b/mailpoet/tests/unit/Validator/Schema/StringSchemaTest.php @@ -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."); + } }