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 { protected function getReservedKeywords(): array {
return rest_get_allowed_schema_keywords(); 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 * @param array<string, Schema> $properties
*/ */
public function patternProperties(array $properties): self { public function patternProperties(array $properties): self {
return $this->updateSchemaProperty('patternProperties', array_map( $patternProperties = [];
function (Schema $property) { foreach ($properties as $key => $value) {
return $property->toArray(); $this->validatePattern($key);
}, $patternProperties[$key] = $value->toArray();
$properties }
)); return $this->updateSchemaProperty('patternProperties', $patternProperties);
} }
public function minProperties(int $value): self { 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 * See: https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#pattern
*/ */
public function pattern(string $pattern): self { public function pattern(string $pattern): self {
$this->validatePattern($pattern);
return $this->updateSchemaProperty('pattern', $pattern); return $this->updateSchemaProperty('pattern', $pattern);
} }

View File

@@ -2,6 +2,7 @@
namespace MailPoet\Validator\Schema; namespace MailPoet\Validator\Schema;
use MailPoet\InvalidStateException;
use MailPoet\Validator\Schema; use MailPoet\Validator\Schema;
use MailPoetUnitTest; use MailPoetUnitTest;
@@ -104,6 +105,11 @@ class ObjectSchemaTest extends MailPoetUnitTest {
'{"type":"object","patternProperties":{"^number-[0-9]+":{"type":"number"},"^string-[0-9]+":{"type":"string"}}}', '{"type":"object","patternProperties":{"^number-[0-9]+":{"type":"number"},"^string-[0-9]+":{"type":"string"}}}',
$object->toString() $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 { public function testMinProperties(): void {
@@ -174,4 +180,15 @@ class ObjectSchemaTest extends MailPoetUnitTest {
protected $schema = ['type' => 'string']; 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; namespace MailPoet\Validator\Schema;
use MailPoet\InvalidStateException;
use MailPoetUnitTest; use MailPoetUnitTest;
class StringSchemaTest extends MailPoetUnitTest { class StringSchemaTest extends MailPoetUnitTest {
@@ -27,6 +28,11 @@ class StringSchemaTest extends MailPoetUnitTest {
$string = (new StringSchema())->pattern('[0-9]+'); $string = (new StringSchema())->pattern('[0-9]+');
$this->assertSame(['type' => 'string', 'pattern' => '[0-9]+'], $string->toArray()); $this->assertSame(['type' => 'string', 'pattern' => '[0-9]+'], $string->toArray());
$this->assertSame('{"type":"string","pattern":"[0-9]+"}', $string->toString()); $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 { public function testFormat(): void {
@@ -88,4 +94,15 @@ class StringSchemaTest extends MailPoetUnitTest {
$this->assertNotSame($string->formatUri(), $string); $this->assertNotSame($string->formatUri(), $string);
$this->assertNotSame($string->formatUuid(), $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.");
}
} }