From a98f828e4b4c1872c791004d7f3d4100329004c6 Mon Sep 17 00:00:00 2001 From: Ninos Date: Thu, 28 Sep 2023 23:26:14 +0200 Subject: [PATCH 01/31] Enhancement: Add *_ONLY_PRIV & *_ONLY_RES as possible versions in IP constraint Added: MAC address constraint Changed: Default version filter from IPv4 to ALL (IPv4 & IPv6) --- .../Component/Validator/Constraints/Ip.php | 22 ++++++- .../Validator/Constraints/IpValidator.php | 23 ++++++-- .../Component/Validator/Constraints/Mac.php | 59 +++++++++++++++++++ .../Validator/Constraints/MacValidator.php | 53 +++++++++++++++++ 4 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 src/Symfony/Component/Validator/Constraints/Mac.php create mode 100644 src/Symfony/Component/Validator/Constraints/MacValidator.php diff --git a/src/Symfony/Component/Validator/Constraints/Ip.php b/src/Symfony/Component/Validator/Constraints/Ip.php index 955a898f898f7..ad18867559fcb 100644 --- a/src/Symfony/Component/Validator/Constraints/Ip.php +++ b/src/Symfony/Component/Validator/Constraints/Ip.php @@ -23,6 +23,7 @@ * * @author Bernhard Schussek * @author Joseph Bielawski + * @author Ninos Ego */ #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class Ip extends Constraint @@ -46,6 +47,16 @@ class Ip extends Constraint public const V6_ONLY_PUBLIC = '6_public'; public const ALL_ONLY_PUBLIC = 'all_public'; + // adds inverse FILTER_FLAG_NO_PRIV_RANGE + public const V4_ONLY_PRIV = '4_priv'; + public const V6_ONLY_PRIV = '6_priv'; + public const ALL_ONLY_PRIV = 'all_priv'; + + // adds inverse FILTER_FLAG_NO_RES_RANGE + public const V4_ONLY_RES = '4_res'; + public const V6_ONLY_RES = '6_res'; + public const ALL_ONLY_RES = 'all_res'; + public const INVALID_IP_ERROR = 'b1b427ae-9f6f-41b0-aa9b-84511fbb3c5b'; protected const VERSIONS = [ @@ -64,6 +75,14 @@ class Ip extends Constraint self::V4_ONLY_PUBLIC, self::V6_ONLY_PUBLIC, self::ALL_ONLY_PUBLIC, + + self::V4_ONLY_PRIV, + self::V6_ONLY_PRIV, + self::ALL_ONLY_PRIV, + + self::V4_ONLY_RES, + self::V6_ONLY_RES, + self::ALL_ONLY_RES, ]; protected const ERROR_NAMES = [ @@ -80,11 +99,10 @@ class Ip extends Constraint */ protected static $errorNames = self::ERROR_NAMES; - public $version = self::V4; + public $version = self::ALL; public $message = 'This is not a valid IP address.'; - /** @var callable|null */ public $normalizer; public function __construct( diff --git a/src/Symfony/Component/Validator/Constraints/IpValidator.php b/src/Symfony/Component/Validator/Constraints/IpValidator.php index 2f71a880450c4..35f30384cb5af 100644 --- a/src/Symfony/Component/Validator/Constraints/IpValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IpValidator.php @@ -21,12 +21,10 @@ * * @author Bernhard Schussek * @author Joseph Bielawski + * @author Ninos Ego */ class IpValidator extends ConstraintValidator { - /** - * @return void - */ public function validate(mixed $value, Constraint $constraint) { if (!$constraint instanceof Ip) { @@ -48,8 +46,8 @@ public function validate(mixed $value, Constraint $constraint) } $flag = match ($constraint->version) { - Ip::V4 => \FILTER_FLAG_IPV4, - Ip::V6 => \FILTER_FLAG_IPV6, + Ip::V4, Ip::V4_ONLY_PRIV, Ip::V4_ONLY_RES => \FILTER_FLAG_IPV4, + Ip::V6, Ip::V6_ONLY_PRIV, Ip::V6_ONLY_RES => \FILTER_FLAG_IPV6, Ip::V4_NO_PRIV => \FILTER_FLAG_IPV4 | \FILTER_FLAG_NO_PRIV_RANGE, Ip::V6_NO_PRIV => \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_PRIV_RANGE, Ip::ALL_NO_PRIV => \FILTER_FLAG_NO_PRIV_RANGE, @@ -67,6 +65,21 @@ public function validate(mixed $value, Constraint $constraint) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Ip::INVALID_IP_ERROR) ->addViolation(); + + return; + } + + $inverseFlag = match ($constraint->version) { + Ip::V4_ONLY_PRIV, Ip::V6_ONLY_PRIV, Ip::ALL_ONLY_PRIV => \FILTER_FLAG_NO_PRIV_RANGE, + Ip::V4_ONLY_RES, Ip::V6_ONLY_RES, Ip::ALL_ONLY_RES => \FILTER_FLAG_NO_RES_RANGE, + default => 0, + }; + + if ($inverseFlag && filter_var($value, \FILTER_VALIDATE_IP, $inverseFlag)) { + $this->context->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Ip::INVALID_IP_ERROR) + ->addViolation(); } } } diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php new file mode 100644 index 0000000000000..dd107fcded865 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Mac.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidArgumentException; + +/** + * Validates that a value is a valid MAC address. + * + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Ninos Ego + */ +#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class Mac extends Constraint +{ + public const INVALID_MAC_ERROR = 'a183fbff-6968-43b4-82a2-cc5cf7150036'; + + protected const ERROR_NAMES = [ + self::INVALID_MAC_ERROR => 'INVALID_MAC_ERROR', + ]; + + /** + * @deprecated since Symfony 6.1, use const ERROR_NAMES instead + */ + protected static $errorNames = self::ERROR_NAMES; + + public $message = 'This is not a valid MAC address.'; + + public $normalizer; + + public function __construct( + array $options = null, + string $message = null, + callable $normalizer = null, + array $groups = null, + mixed $payload = null + ) { + parent::__construct($options, $groups, $payload); + + $this->message = $message ?? $this->message; + $this->normalizer = $normalizer ?? $this->normalizer; + + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', get_debug_type($this->normalizer))); + } + } +} diff --git a/src/Symfony/Component/Validator/Constraints/MacValidator.php b/src/Symfony/Component/Validator/Constraints/MacValidator.php new file mode 100644 index 0000000000000..740f0a5b3611c --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/MacValidator.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Validator\Exception\UnexpectedValueException; + +/** + * Validates whether a value is a valid MAC address. + * + * @author Ninos Ego + */ +class MacValidator extends ConstraintValidator +{ + public function validate(mixed $value, Constraint $constraint) + { + if (!$constraint instanceof Mac) { + throw new UnexpectedTypeException($constraint, Mac::class); + } + + if (null === $value || '' === $value) { + return; + } + + if (!\is_scalar($value) && !$value instanceof \Stringable) { + throw new UnexpectedValueException($value, 'string'); + } + + $value = (string) $value; + + if (null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + + if (!filter_var($value, \FILTER_VALIDATE_MAC)) { + $this->context->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Mac::INVALID_MAC_ERROR) + ->addViolation(); + } + } +} From 9551dc39b8f90babe9fd9b9ad39b1e28248b5e0f Mon Sep 17 00:00:00 2001 From: Ninos Date: Thu, 28 Sep 2023 23:31:41 +0200 Subject: [PATCH 02/31] Updated: Changelog --- src/Symfony/Component/Validator/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index addca159de6a3..3484d05cb3033 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,6 +4,9 @@ CHANGELOG 6.4 --- + * Add `Mac` constraint + * Add `*_ONLY_PRIV` and `*_ONLY_RES` versions to `Ip` constraint + * Change default version from `V4` to `ALL` in `Ip` constraint * Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate` * Allow single integer for the `versions` option of the `Uuid` constraint * Allow single constraint to be passed to the `constraints` option of the `When` constraint From 2b1e88871305e3233ab74f8e92e31df4e39f5b4e Mon Sep 17 00:00:00 2001 From: Ninos Date: Thu, 28 Sep 2023 23:37:37 +0200 Subject: [PATCH 03/31] Updated: UPGRADE-6.4.md --- UPGRADE-6.4.md | 1 + 1 file changed, 1 insertion(+) diff --git a/UPGRADE-6.4.md b/UPGRADE-6.4.md index 280d06a073b5d..97efab0f25e88 100644 --- a/UPGRADE-6.4.md +++ b/UPGRADE-6.4.md @@ -157,6 +157,7 @@ Templating Validator --------- + * Changed default version flag from `V4` to `ALL` (also `V6`) in `Ip` constraint * Deprecate Doctrine annotations support in favor of native attributes * Deprecate `ValidatorBuilder::setDoctrineAnnotationReader()` * Deprecate `ValidatorBuilder::addDefaultDoctrineAnnotationReader()` From 24c73a31f37f1595ab45dcab0b84723876bebf8e Mon Sep 17 00:00:00 2001 From: Ninos Date: Thu, 28 Sep 2023 23:40:41 +0200 Subject: [PATCH 04/31] CS --- src/Symfony/Component/Validator/Constraints/Ip.php | 1 + src/Symfony/Component/Validator/Constraints/IpValidator.php | 3 +++ src/Symfony/Component/Validator/Constraints/Mac.php | 1 + src/Symfony/Component/Validator/Constraints/MacValidator.php | 3 +++ 4 files changed, 8 insertions(+) diff --git a/src/Symfony/Component/Validator/Constraints/Ip.php b/src/Symfony/Component/Validator/Constraints/Ip.php index ad18867559fcb..27c25cd50002c 100644 --- a/src/Symfony/Component/Validator/Constraints/Ip.php +++ b/src/Symfony/Component/Validator/Constraints/Ip.php @@ -103,6 +103,7 @@ class Ip extends Constraint public $message = 'This is not a valid IP address.'; + /** @var callable|null */ public $normalizer; public function __construct( diff --git a/src/Symfony/Component/Validator/Constraints/IpValidator.php b/src/Symfony/Component/Validator/Constraints/IpValidator.php index 35f30384cb5af..3947721140ac8 100644 --- a/src/Symfony/Component/Validator/Constraints/IpValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IpValidator.php @@ -25,6 +25,9 @@ */ class IpValidator extends ConstraintValidator { + /** + * @return void + */ public function validate(mixed $value, Constraint $constraint) { if (!$constraint instanceof Ip) { diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php index dd107fcded865..da65535cdedc0 100644 --- a/src/Symfony/Component/Validator/Constraints/Mac.php +++ b/src/Symfony/Component/Validator/Constraints/Mac.php @@ -38,6 +38,7 @@ class Mac extends Constraint public $message = 'This is not a valid MAC address.'; + /** @var callable|null */ public $normalizer; public function __construct( diff --git a/src/Symfony/Component/Validator/Constraints/MacValidator.php b/src/Symfony/Component/Validator/Constraints/MacValidator.php index 740f0a5b3611c..c03cacc3b6282 100644 --- a/src/Symfony/Component/Validator/Constraints/MacValidator.php +++ b/src/Symfony/Component/Validator/Constraints/MacValidator.php @@ -23,6 +23,9 @@ */ class MacValidator extends ConstraintValidator { + /** + * @return void + */ public function validate(mixed $value, Constraint $constraint) { if (!$constraint instanceof Mac) { From 2200cd82911e63b513b6781d871fa8613d08f66f Mon Sep 17 00:00:00 2001 From: Ninos Date: Fri, 29 Sep 2023 00:06:59 +0200 Subject: [PATCH 05/31] Added: Tests for `Mac` constraint Fixed: Test for `Ip` constraint --- .../Validator/Tests/Constraints/IpTest.php | 2 +- .../Tests/Constraints/IpValidatorTest.php | 2 +- .../Validator/Tests/Constraints/MacTest.php | 70 ++++++++++ .../Tests/Constraints/MacValidatorTest.php | 125 ++++++++++++++++++ 4 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/MacTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/MacValidatorTest.php diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php index 7f391153f3a69..6fb96369e2cf6 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php @@ -50,7 +50,7 @@ public function testAttributes() self::assertTrue($loader->loadClassMetadata($metadata)); [$aConstraint] = $metadata->properties['a']->getConstraints(); - self::assertSame(Ip::V4, $aConstraint->version); + self::assertSame(Ip::ALL, $aConstraint->version); [$bConstraint] = $metadata->properties['b']->getConstraints(); self::assertSame(Ip::V6, $bConstraint->version); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php index 2a0bdcf70495a..82068184d9647 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php @@ -95,7 +95,7 @@ public function testValidIpV6WithWhitespacesNamed() { $this->validator->validate( "\n\t2001:0db8:85a3:0000:0000:8a2e:0370:7334\r\n", - new Ip(version: \Symfony\Component\Validator\Constraints\Ip::V6, normalizer: 'trim') + new Ip(version: Ip::V6, normalizer: 'trim') ); $this->assertNoViolation(); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php b/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php new file mode 100644 index 0000000000000..b542ee0237f39 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\Mac; +use Symfony\Component\Validator\Exception\InvalidArgumentException; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Mapping\Loader\AttributeLoader; + +/** + * @author Ninos Ego + */ +class MacTest extends TestCase +{ + public function testNormalizerCanBeSet() + { + $ip = new Mac(['normalizer' => 'trim']); + + $this->assertEquals('trim', $ip->normalizer); + } + + public function testInvalidNormalizerThrowsException() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "normalizer" option must be a valid callable ("string" given).'); + new Mac(['normalizer' => 'Unknown Callable']); + } + + public function testInvalidNormalizerObjectThrowsException() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "normalizer" option must be a valid callable ("stdClass" given).'); + new Mac(['normalizer' => new \stdClass()]); + } + + public function testAttributes() + { + $metadata = new ClassMetadata(IpDummy::class); + $loader = new AttributeLoader(); + self::assertTrue($loader->loadClassMetadata($metadata)); + + [$aConstraint] = $metadata->properties['a']->getConstraints(); + self::assertSame('myMessage', $aConstraint->message); + self::assertSame('trim', $aConstraint->normalizer); + self::assertSame(['Default', 'IpDummy'], $aConstraint->groups); + + [$bConstraint] = $metadata->properties['b']->getConstraints(); + self::assertSame(['my_group'], $bConstraint->groups); + self::assertSame('some attached data', $bConstraint->payload); + } +} + +class MacDummy +{ + #[Mac( message: 'myMessage', normalizer: 'trim')] + private $a; + + #[Mac(groups: ['my_group'], payload: 'some attached data')] + private $b; +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/MacValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/MacValidatorTest.php new file mode 100644 index 0000000000000..be62cb28cf1e7 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/MacValidatorTest.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Mac; +use Symfony\Component\Validator\Constraints\MacValidator; +use Symfony\Component\Validator\Exception\UnexpectedValueException; +use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; + +/** + * @author Ninos Ego + */ +class MacValidatorTest extends ConstraintValidatorTestCase +{ + protected function createValidator(): MacValidator + { + return new MacValidator(); + } + + public function testNullIsValid() + { + $this->validator->validate(null, new Mac()); + + $this->assertNoViolation(); + } + + public function testEmptyStringIsValid() + { + $this->validator->validate('', new Mac()); + + $this->assertNoViolation(); + } + + public function testExpectsStringCompatibleType() + { + $this->expectException(UnexpectedValueException::class); + $this->validator->validate(new \stdClass(), new Mac()); + } + + /** + * @dataProvider getValidMacs + */ + public function testValidMac($mac) + { + $this->validator->validate($mac, new Mac()); + + $this->assertNoViolation(); + } + + public static function getValidMacs() + { + return [ + ['00:00:00:00:00:00'], + ['00-00-00-00-00-00'], + ['ff:ff:ff:ff:ff:ff'], + ['ff-ff-ff-ff-ff-ff'], + ['FF:FF:FF:FF:FF:FF'], + ['FF-FF-FF-FF-FF-FF'], + ]; + } + + /** + * @dataProvider getValidMacsWithWhitespaces + */ + public function testValidMacsWithWhitespaces($mac) + { + $this->validator->validate($mac, new Mac([ + 'normalizer' => 'trim', + ])); + + $this->assertNoViolation(); + } + + public static function getValidMacsWithWhitespaces() + { + return [ + ["\x2000:00:00:00:00:00"], + ["\x09\x0900-00-00-00-00-00"], + ["ff:ff:ff:ff:ff:ff\x0A"], + ["ff-ff-ff-ff-ff-ff\x0D\x0D"], + ["\x00FF:FF:FF:FF:FF:FF\x00"], + ["\x0B\x0BFF-FF-FF-FF-FF-FF\x0B\x0B"], + ]; + } + + /** + * @dataProvider getInvalidMacs + */ + public function testInvalidMacs($mac) + { + $constraint = new Mac([ + 'message' => 'myMessage', + ]); + + $this->validator->validate($mac, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '"'.$mac.'"') + ->setCode(Mac::INVALID_MAC_ERROR) + ->assertRaised(); + } + + public static function getInvalidMacs() + { + return [ + ['0'], + ['00:00'], + ['00:00:00'], + ['00:00:00:00'], + ['00:00:00:00:00'], + ['00:00:00:00:00:000'], + ['-00:00:00:00:00:00'], + ['foobar'], + ]; + } +} From 3cb31192ece69d90207395a39d021ab41e45c2b1 Mon Sep 17 00:00:00 2001 From: Ninos Date: Fri, 29 Sep 2023 00:18:15 +0200 Subject: [PATCH 06/31] Fixed: Tests for `Mac` constraint --- .../Component/Validator/Tests/Constraints/MacTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php b/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php index b542ee0237f39..1bf59fd3c7f54 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php @@ -24,9 +24,9 @@ class MacTest extends TestCase { public function testNormalizerCanBeSet() { - $ip = new Mac(['normalizer' => 'trim']); + $mac = new Mac(['normalizer' => 'trim']); - $this->assertEquals('trim', $ip->normalizer); + $this->assertEquals('trim', $mac->normalizer); } public function testInvalidNormalizerThrowsException() @@ -45,14 +45,14 @@ public function testInvalidNormalizerObjectThrowsException() public function testAttributes() { - $metadata = new ClassMetadata(IpDummy::class); + $metadata = new ClassMetadata(MacDummy::class); $loader = new AttributeLoader(); self::assertTrue($loader->loadClassMetadata($metadata)); [$aConstraint] = $metadata->properties['a']->getConstraints(); self::assertSame('myMessage', $aConstraint->message); self::assertSame('trim', $aConstraint->normalizer); - self::assertSame(['Default', 'IpDummy'], $aConstraint->groups); + self::assertSame(['Default', 'MacDummy'], $aConstraint->groups); [$bConstraint] = $metadata->properties['b']->getConstraints(); self::assertSame(['my_group'], $bConstraint->groups); From 99e03ea1fe40b685f2f5bb9197c317ffa6b40de9 Mon Sep 17 00:00:00 2001 From: Ninos Date: Fri, 29 Sep 2023 00:32:57 +0200 Subject: [PATCH 07/31] Added: OnlyPrivate & OnlyReserved tests --- .../Tests/Constraints/IpValidatorTest.php | 74 +++++++++++++++++-- 1 file changed, 67 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php index 82068184d9647..0a0165b062eb1 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php @@ -201,7 +201,19 @@ public static function getInvalidIpsV4() } /** - * @dataProvider getInvalidPrivateIpsV4 + * @dataProvider getValidPrivateIpsV4 + */ + public function testValidPrivateIpsV4($ip) + { + $this->validator->validate($ip, new Ip([ + 'version' => Ip::V4_ONLY_PRIV, + ])); + + $this->assertNoViolation(); + } + + /** + * @dataProvider getValidPrivateIpsV4 */ public function testInvalidPrivateIpsV4($ip) { @@ -218,7 +230,25 @@ public function testInvalidPrivateIpsV4($ip) ->assertRaised(); } - public static function getInvalidPrivateIpsV4() + /** + * @dataProvider getValidReservedIpsV4 + */ + public function testInvalidOnlyPrivateIpsV4($ip) + { + $constraint = new Ip([ + 'version' => Ip::V4_ONLY_PRIV, + 'message' => 'myMessage', + ]); + + $this->validator->validate($ip, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '"'.$ip.'"') + ->setCode(Ip::INVALID_IP_ERROR) + ->assertRaised(); + } + + public static function getValidPrivateIpsV4() { return [ ['10.0.0.0'], @@ -228,7 +258,19 @@ public static function getInvalidPrivateIpsV4() } /** - * @dataProvider getInvalidReservedIpsV4 + * @dataProvider getValidReservedIpsV4 + */ + public function testValidReservedIpsV4($ip) + { + $this->validator->validate($ip, new Ip([ + 'version' => Ip::V4_ONLY_RES, + ])); + + $this->assertNoViolation(); + } + + /** + * @dataProvider getValidReservedIpsV4 */ public function testInvalidReservedIpsV4($ip) { @@ -245,7 +287,25 @@ public function testInvalidReservedIpsV4($ip) ->assertRaised(); } - public static function getInvalidReservedIpsV4() + /** + * @dataProvider getValidPrivateIpsV4 + */ + public function testInvalidOnlyReservedIpsV4($ip) + { + $constraint = new Ip([ + 'version' => Ip::V4_ONLY_RES, + 'message' => 'myMessage', + ]); + + $this->validator->validate($ip, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '"'.$ip.'"') + ->setCode(Ip::INVALID_IP_ERROR) + ->assertRaised(); + } + + public static function getValidReservedIpsV4() { return [ ['0.0.0.0'], @@ -274,7 +334,7 @@ public function testInvalidPublicIpsV4($ip) public static function getInvalidPublicIpsV4() { - return array_merge(self::getInvalidPrivateIpsV4(), self::getInvalidReservedIpsV4()); + return array_merge(self::getValidPrivateIpsV4(), self::getValidReservedIpsV4()); } /** @@ -433,7 +493,7 @@ public function testInvalidPrivateIpsAll($ip) public static function getInvalidPrivateIpsAll() { - return array_merge(self::getInvalidPrivateIpsV4(), self::getInvalidPrivateIpsV6()); + return array_merge(self::getValidPrivateIpsV4(), self::getInvalidPrivateIpsV6()); } /** @@ -456,7 +516,7 @@ public function testInvalidReservedIpsAll($ip) public static function getInvalidReservedIpsAll() { - return array_merge(self::getInvalidReservedIpsV4(), self::getInvalidReservedIpsV6()); + return array_merge(self::getValidReservedIpsV4(), self::getInvalidReservedIpsV6()); } /** From c11c261a96c7d47e816647708a444764624778b3 Mon Sep 17 00:00:00 2001 From: Ninos Date: Fri, 29 Sep 2023 00:49:56 +0200 Subject: [PATCH 08/31] Enhancement: OnlyPrivate & OnlyReserved tests --- .../Tests/Constraints/IpValidatorTest.php | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php index 0a0165b062eb1..4791e1c0d6acb 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php @@ -185,6 +185,15 @@ public function testInvalidIpsV4($ip) ->assertRaised(); } + public static function getValidPublicIpsV4() + { + return [ + ['8.0.0.0'], + ['90.0.0.0'], + ['110.0.0.110'], + ]; + } + public static function getInvalidIpsV4() { return [ @@ -231,7 +240,7 @@ public function testInvalidPrivateIpsV4($ip) } /** - * @dataProvider getValidReservedIpsV4 + * @dataProvider getInvalidPrivateIpsV4 */ public function testInvalidOnlyPrivateIpsV4($ip) { @@ -257,6 +266,11 @@ public static function getValidPrivateIpsV4() ]; } + public static function getInvalidPrivateIpsV4() + { + return array_merge(self::getValidPublicIpsV4(), self::getValidReservedIpsV4()); + } + /** * @dataProvider getValidReservedIpsV4 */ @@ -288,7 +302,7 @@ public function testInvalidReservedIpsV4($ip) } /** - * @dataProvider getValidPrivateIpsV4 + * @dataProvider getInvalidReservedIpsV4 */ public function testInvalidOnlyReservedIpsV4($ip) { @@ -314,6 +328,11 @@ public static function getValidReservedIpsV4() ]; } + public static function getInvalidReservedIpsV4() + { + return array_merge(self::getValidPublicIpsV4(), self::getValidPrivateIpsV4()); + } + /** * @dataProvider getInvalidPublicIpsV4 */ From 12f126e9864d458e05afd174c7cb84ca1bb8c8dc Mon Sep 17 00:00:00 2001 From: Ninos Date: Fri, 29 Sep 2023 01:01:16 +0200 Subject: [PATCH 09/31] CS --- src/Symfony/Component/Validator/Constraints/Ip.php | 1 + src/Symfony/Component/Validator/Constraints/Mac.php | 1 + src/Symfony/Component/Validator/Tests/Constraints/MacTest.php | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/Ip.php b/src/Symfony/Component/Validator/Constraints/Ip.php index 27c25cd50002c..b1445d22d60b4 100644 --- a/src/Symfony/Component/Validator/Constraints/Ip.php +++ b/src/Symfony/Component/Validator/Constraints/Ip.php @@ -19,6 +19,7 @@ * Validates that a value is a valid IP address. * * @Annotation + * * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) * * @author Bernhard Schussek diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php index da65535cdedc0..b9dca8510ba83 100644 --- a/src/Symfony/Component/Validator/Constraints/Mac.php +++ b/src/Symfony/Component/Validator/Constraints/Mac.php @@ -18,6 +18,7 @@ * Validates that a value is a valid MAC address. * * @Annotation + * * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) * * @author Ninos Ego diff --git a/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php b/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php index 1bf59fd3c7f54..9209dcba9af46 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php @@ -62,7 +62,7 @@ public function testAttributes() class MacDummy { - #[Mac( message: 'myMessage', normalizer: 'trim')] + #[Mac(message: 'myMessage', normalizer: 'trim')] private $a; #[Mac(groups: ['my_group'], payload: 'some attached data')] From e4e6a24b317edfcc4beb3d05e2cf721e2b0527b2 Mon Sep 17 00:00:00 2001 From: Ninos Ego Date: Thu, 5 Oct 2023 08:11:08 +0200 Subject: [PATCH 10/31] Update src/Symfony/Component/Validator/Constraints/Mac.php Co-authored-by: Nicolas Grekas --- src/Symfony/Component/Validator/Constraints/Mac.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php index b9dca8510ba83..da65535cdedc0 100644 --- a/src/Symfony/Component/Validator/Constraints/Mac.php +++ b/src/Symfony/Component/Validator/Constraints/Mac.php @@ -18,7 +18,6 @@ * Validates that a value is a valid MAC address. * * @Annotation - * * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) * * @author Ninos Ego From 0e6cf5e6cf665b8ad5ab047f89428943c0edd6e9 Mon Sep 17 00:00:00 2001 From: Ninos Ego Date: Thu, 5 Oct 2023 08:11:48 +0200 Subject: [PATCH 11/31] Update src/Symfony/Component/Validator/Constraints/Ip.php Co-authored-by: Nicolas Grekas --- src/Symfony/Component/Validator/Constraints/Ip.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/Ip.php b/src/Symfony/Component/Validator/Constraints/Ip.php index b1445d22d60b4..2993389ffa42b 100644 --- a/src/Symfony/Component/Validator/Constraints/Ip.php +++ b/src/Symfony/Component/Validator/Constraints/Ip.php @@ -100,7 +100,7 @@ class Ip extends Constraint */ protected static $errorNames = self::ERROR_NAMES; - public $version = self::ALL; + public $version = self::V4; public $message = 'This is not a valid IP address.'; From 0b7910f84511cdd7a46fb4430c16adb648350c9a Mon Sep 17 00:00:00 2001 From: Ninos Ego Date: Thu, 5 Oct 2023 08:12:17 +0200 Subject: [PATCH 12/31] Update src/Symfony/Component/Validator/Constraints/MacValidator.php Co-authored-by: Nicolas Grekas --- src/Symfony/Component/Validator/Constraints/MacValidator.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/MacValidator.php b/src/Symfony/Component/Validator/Constraints/MacValidator.php index c03cacc3b6282..7f23e7817db74 100644 --- a/src/Symfony/Component/Validator/Constraints/MacValidator.php +++ b/src/Symfony/Component/Validator/Constraints/MacValidator.php @@ -23,10 +23,7 @@ */ class MacValidator extends ConstraintValidator { - /** - * @return void - */ - public function validate(mixed $value, Constraint $constraint) + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof Mac) { throw new UnexpectedTypeException($constraint, Mac::class); From 719be6cd3352f31745179aa8ee6392c5347db129 Mon Sep 17 00:00:00 2001 From: Ninos Ego Date: Thu, 5 Oct 2023 08:12:47 +0200 Subject: [PATCH 13/31] Update src/Symfony/Component/Validator/Constraints/Mac.php Co-authored-by: Nicolas Grekas --- src/Symfony/Component/Validator/Constraints/Mac.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php index da65535cdedc0..c572cc70da017 100644 --- a/src/Symfony/Component/Validator/Constraints/Mac.php +++ b/src/Symfony/Component/Validator/Constraints/Mac.php @@ -46,7 +46,7 @@ public function __construct( string $message = null, callable $normalizer = null, array $groups = null, - mixed $payload = null + mixed $payload = null, ) { parent::__construct($options, $groups, $payload); From a6eb4f224e728b1e57b62d0b0b6927d5756bf00d Mon Sep 17 00:00:00 2001 From: Ninos Ego Date: Thu, 5 Oct 2023 08:13:15 +0200 Subject: [PATCH 14/31] Update src/Symfony/Component/Validator/Constraints/Mac.php Co-authored-by: Nicolas Grekas --- src/Symfony/Component/Validator/Constraints/Mac.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php index c572cc70da017..945062cc97e90 100644 --- a/src/Symfony/Component/Validator/Constraints/Mac.php +++ b/src/Symfony/Component/Validator/Constraints/Mac.php @@ -23,7 +23,7 @@ * @author Ninos Ego */ #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] -class Mac extends Constraint +class MacAddress extends Constraint { public const INVALID_MAC_ERROR = 'a183fbff-6968-43b4-82a2-cc5cf7150036'; From 4b4c5e4deaf7f6d6571633597fe9a31de5c82f1f Mon Sep 17 00:00:00 2001 From: Ninos Ego Date: Thu, 5 Oct 2023 08:13:27 +0200 Subject: [PATCH 15/31] Update src/Symfony/Component/Validator/Constraints/Mac.php Co-authored-by: Nicolas Grekas --- src/Symfony/Component/Validator/Constraints/Mac.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php index 945062cc97e90..405732b981454 100644 --- a/src/Symfony/Component/Validator/Constraints/Mac.php +++ b/src/Symfony/Component/Validator/Constraints/Mac.php @@ -36,7 +36,7 @@ class MacAddress extends Constraint */ protected static $errorNames = self::ERROR_NAMES; - public $message = 'This is not a valid MAC address.'; + public string $message = 'This is not a valid MAC address.'; /** @var callable|null */ public $normalizer; From 9cf46fca67d346b908591a6622b1745e30eac2b7 Mon Sep 17 00:00:00 2001 From: Ninos Ego Date: Thu, 5 Oct 2023 08:13:36 +0200 Subject: [PATCH 16/31] Update src/Symfony/Component/Validator/Constraints/Mac.php Co-authored-by: Nicolas Grekas --- src/Symfony/Component/Validator/Constraints/Mac.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php index 405732b981454..b4fbf2e05af17 100644 --- a/src/Symfony/Component/Validator/Constraints/Mac.php +++ b/src/Symfony/Component/Validator/Constraints/Mac.php @@ -31,11 +31,6 @@ class MacAddress extends Constraint self::INVALID_MAC_ERROR => 'INVALID_MAC_ERROR', ]; - /** - * @deprecated since Symfony 6.1, use const ERROR_NAMES instead - */ - protected static $errorNames = self::ERROR_NAMES; - public string $message = 'This is not a valid MAC address.'; /** @var callable|null */ From 9775156e3034873027a08b7cb5f4c08092181057 Mon Sep 17 00:00:00 2001 From: Ninos Date: Thu, 5 Oct 2023 08:24:04 +0200 Subject: [PATCH 17/31] CS --- UPGRADE-6.4.md | 1 - src/Symfony/Component/Validator/CHANGELOG.md | 1 - src/Symfony/Component/Validator/Constraints/Ip.php | 1 - src/Symfony/Component/Validator/Constraints/Mac.php | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/UPGRADE-6.4.md b/UPGRADE-6.4.md index 97efab0f25e88..280d06a073b5d 100644 --- a/UPGRADE-6.4.md +++ b/UPGRADE-6.4.md @@ -157,7 +157,6 @@ Templating Validator --------- - * Changed default version flag from `V4` to `ALL` (also `V6`) in `Ip` constraint * Deprecate Doctrine annotations support in favor of native attributes * Deprecate `ValidatorBuilder::setDoctrineAnnotationReader()` * Deprecate `ValidatorBuilder::addDefaultDoctrineAnnotationReader()` diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 3484d05cb3033..f2271f3674e78 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -6,7 +6,6 @@ CHANGELOG * Add `Mac` constraint * Add `*_ONLY_PRIV` and `*_ONLY_RES` versions to `Ip` constraint - * Change default version from `V4` to `ALL` in `Ip` constraint * Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate` * Allow single integer for the `versions` option of the `Uuid` constraint * Allow single constraint to be passed to the `constraints` option of the `When` constraint diff --git a/src/Symfony/Component/Validator/Constraints/Ip.php b/src/Symfony/Component/Validator/Constraints/Ip.php index 2993389ffa42b..7e8d8d448bb06 100644 --- a/src/Symfony/Component/Validator/Constraints/Ip.php +++ b/src/Symfony/Component/Validator/Constraints/Ip.php @@ -19,7 +19,6 @@ * Validates that a value is a valid IP address. * * @Annotation - * * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) * * @author Bernhard Schussek diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php index b4fbf2e05af17..2a60cd115357a 100644 --- a/src/Symfony/Component/Validator/Constraints/Mac.php +++ b/src/Symfony/Component/Validator/Constraints/Mac.php @@ -23,7 +23,7 @@ * @author Ninos Ego */ #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] -class MacAddress extends Constraint +class Mac extends Constraint { public const INVALID_MAC_ERROR = 'a183fbff-6968-43b4-82a2-cc5cf7150036'; From 646fd5f8b61dafe6eeebf2acb2a41bca3f5b6750 Mon Sep 17 00:00:00 2001 From: Ninos Date: Fri, 6 Oct 2023 07:44:25 +0200 Subject: [PATCH 18/31] Removed: Mac constraint --- src/Symfony/Component/Validator/CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index f2271f3674e78..03939663fff12 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,7 +4,6 @@ CHANGELOG 6.4 --- - * Add `Mac` constraint * Add `*_ONLY_PRIV` and `*_ONLY_RES` versions to `Ip` constraint * Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate` * Allow single integer for the `versions` option of the `Uuid` constraint From 26e9f2ab26730e114bd7ac2a2a7dc6baa5e43750 Mon Sep 17 00:00:00 2001 From: Ninos Date: Fri, 6 Oct 2023 07:48:40 +0200 Subject: [PATCH 19/31] [Validator] Remove `Mac` constraint --- .../Component/Validator/Constraints/Mac.php | 55 -------- .../Validator/Constraints/MacValidator.php | 53 -------- .../Validator/Tests/Constraints/MacTest.php | 70 ---------- .../Tests/Constraints/MacValidatorTest.php | 125 ------------------ 4 files changed, 303 deletions(-) delete mode 100644 src/Symfony/Component/Validator/Constraints/Mac.php delete mode 100644 src/Symfony/Component/Validator/Constraints/MacValidator.php delete mode 100644 src/Symfony/Component/Validator/Tests/Constraints/MacTest.php delete mode 100644 src/Symfony/Component/Validator/Tests/Constraints/MacValidatorTest.php diff --git a/src/Symfony/Component/Validator/Constraints/Mac.php b/src/Symfony/Component/Validator/Constraints/Mac.php deleted file mode 100644 index 2a60cd115357a..0000000000000 --- a/src/Symfony/Component/Validator/Constraints/Mac.php +++ /dev/null @@ -1,55 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Constraints; - -use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\Exception\InvalidArgumentException; - -/** - * Validates that a value is a valid MAC address. - * - * @Annotation - * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) - * - * @author Ninos Ego - */ -#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] -class Mac extends Constraint -{ - public const INVALID_MAC_ERROR = 'a183fbff-6968-43b4-82a2-cc5cf7150036'; - - protected const ERROR_NAMES = [ - self::INVALID_MAC_ERROR => 'INVALID_MAC_ERROR', - ]; - - public string $message = 'This is not a valid MAC address.'; - - /** @var callable|null */ - public $normalizer; - - public function __construct( - array $options = null, - string $message = null, - callable $normalizer = null, - array $groups = null, - mixed $payload = null, - ) { - parent::__construct($options, $groups, $payload); - - $this->message = $message ?? $this->message; - $this->normalizer = $normalizer ?? $this->normalizer; - - if (null !== $this->normalizer && !\is_callable($this->normalizer)) { - throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', get_debug_type($this->normalizer))); - } - } -} diff --git a/src/Symfony/Component/Validator/Constraints/MacValidator.php b/src/Symfony/Component/Validator/Constraints/MacValidator.php deleted file mode 100644 index 7f23e7817db74..0000000000000 --- a/src/Symfony/Component/Validator/Constraints/MacValidator.php +++ /dev/null @@ -1,53 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Constraints; - -use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\ConstraintValidator; -use Symfony\Component\Validator\Exception\UnexpectedTypeException; -use Symfony\Component\Validator\Exception\UnexpectedValueException; - -/** - * Validates whether a value is a valid MAC address. - * - * @author Ninos Ego - */ -class MacValidator extends ConstraintValidator -{ - public function validate(mixed $value, Constraint $constraint): void - { - if (!$constraint instanceof Mac) { - throw new UnexpectedTypeException($constraint, Mac::class); - } - - if (null === $value || '' === $value) { - return; - } - - if (!\is_scalar($value) && !$value instanceof \Stringable) { - throw new UnexpectedValueException($value, 'string'); - } - - $value = (string) $value; - - if (null !== $constraint->normalizer) { - $value = ($constraint->normalizer)($value); - } - - if (!filter_var($value, \FILTER_VALIDATE_MAC)) { - $this->context->buildViolation($constraint->message) - ->setParameter('{{ value }}', $this->formatValue($value)) - ->setCode(Mac::INVALID_MAC_ERROR) - ->addViolation(); - } - } -} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php b/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php deleted file mode 100644 index 9209dcba9af46..0000000000000 --- a/src/Symfony/Component/Validator/Tests/Constraints/MacTest.php +++ /dev/null @@ -1,70 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Tests\Constraints; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Validator\Constraints\Mac; -use Symfony\Component\Validator\Exception\InvalidArgumentException; -use Symfony\Component\Validator\Mapping\ClassMetadata; -use Symfony\Component\Validator\Mapping\Loader\AttributeLoader; - -/** - * @author Ninos Ego - */ -class MacTest extends TestCase -{ - public function testNormalizerCanBeSet() - { - $mac = new Mac(['normalizer' => 'trim']); - - $this->assertEquals('trim', $mac->normalizer); - } - - public function testInvalidNormalizerThrowsException() - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('The "normalizer" option must be a valid callable ("string" given).'); - new Mac(['normalizer' => 'Unknown Callable']); - } - - public function testInvalidNormalizerObjectThrowsException() - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('The "normalizer" option must be a valid callable ("stdClass" given).'); - new Mac(['normalizer' => new \stdClass()]); - } - - public function testAttributes() - { - $metadata = new ClassMetadata(MacDummy::class); - $loader = new AttributeLoader(); - self::assertTrue($loader->loadClassMetadata($metadata)); - - [$aConstraint] = $metadata->properties['a']->getConstraints(); - self::assertSame('myMessage', $aConstraint->message); - self::assertSame('trim', $aConstraint->normalizer); - self::assertSame(['Default', 'MacDummy'], $aConstraint->groups); - - [$bConstraint] = $metadata->properties['b']->getConstraints(); - self::assertSame(['my_group'], $bConstraint->groups); - self::assertSame('some attached data', $bConstraint->payload); - } -} - -class MacDummy -{ - #[Mac(message: 'myMessage', normalizer: 'trim')] - private $a; - - #[Mac(groups: ['my_group'], payload: 'some attached data')] - private $b; -} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/MacValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/MacValidatorTest.php deleted file mode 100644 index be62cb28cf1e7..0000000000000 --- a/src/Symfony/Component/Validator/Tests/Constraints/MacValidatorTest.php +++ /dev/null @@ -1,125 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Tests\Constraints; - -use Symfony\Component\Validator\Constraints\Mac; -use Symfony\Component\Validator\Constraints\MacValidator; -use Symfony\Component\Validator\Exception\UnexpectedValueException; -use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; - -/** - * @author Ninos Ego - */ -class MacValidatorTest extends ConstraintValidatorTestCase -{ - protected function createValidator(): MacValidator - { - return new MacValidator(); - } - - public function testNullIsValid() - { - $this->validator->validate(null, new Mac()); - - $this->assertNoViolation(); - } - - public function testEmptyStringIsValid() - { - $this->validator->validate('', new Mac()); - - $this->assertNoViolation(); - } - - public function testExpectsStringCompatibleType() - { - $this->expectException(UnexpectedValueException::class); - $this->validator->validate(new \stdClass(), new Mac()); - } - - /** - * @dataProvider getValidMacs - */ - public function testValidMac($mac) - { - $this->validator->validate($mac, new Mac()); - - $this->assertNoViolation(); - } - - public static function getValidMacs() - { - return [ - ['00:00:00:00:00:00'], - ['00-00-00-00-00-00'], - ['ff:ff:ff:ff:ff:ff'], - ['ff-ff-ff-ff-ff-ff'], - ['FF:FF:FF:FF:FF:FF'], - ['FF-FF-FF-FF-FF-FF'], - ]; - } - - /** - * @dataProvider getValidMacsWithWhitespaces - */ - public function testValidMacsWithWhitespaces($mac) - { - $this->validator->validate($mac, new Mac([ - 'normalizer' => 'trim', - ])); - - $this->assertNoViolation(); - } - - public static function getValidMacsWithWhitespaces() - { - return [ - ["\x2000:00:00:00:00:00"], - ["\x09\x0900-00-00-00-00-00"], - ["ff:ff:ff:ff:ff:ff\x0A"], - ["ff-ff-ff-ff-ff-ff\x0D\x0D"], - ["\x00FF:FF:FF:FF:FF:FF\x00"], - ["\x0B\x0BFF-FF-FF-FF-FF-FF\x0B\x0B"], - ]; - } - - /** - * @dataProvider getInvalidMacs - */ - public function testInvalidMacs($mac) - { - $constraint = new Mac([ - 'message' => 'myMessage', - ]); - - $this->validator->validate($mac, $constraint); - - $this->buildViolation('myMessage') - ->setParameter('{{ value }}', '"'.$mac.'"') - ->setCode(Mac::INVALID_MAC_ERROR) - ->assertRaised(); - } - - public static function getInvalidMacs() - { - return [ - ['0'], - ['00:00'], - ['00:00:00'], - ['00:00:00:00'], - ['00:00:00:00:00'], - ['00:00:00:00:00:000'], - ['-00:00:00:00:00:00'], - ['foobar'], - ]; - } -} From 6e844940eda60f6ccf89a1bc58b87f15dbc82a7d Mon Sep 17 00:00:00 2001 From: Ninos Date: Fri, 6 Oct 2023 07:50:00 +0200 Subject: [PATCH 20/31] [Validator] Fix IpTest --- src/Symfony/Component/Validator/Tests/Constraints/IpTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php index 6fb96369e2cf6..7f391153f3a69 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpTest.php @@ -50,7 +50,7 @@ public function testAttributes() self::assertTrue($loader->loadClassMetadata($metadata)); [$aConstraint] = $metadata->properties['a']->getConstraints(); - self::assertSame(Ip::ALL, $aConstraint->version); + self::assertSame(Ip::V4, $aConstraint->version); [$bConstraint] = $metadata->properties['b']->getConstraints(); self::assertSame(Ip::V6, $bConstraint->version); From cfff49ab973b7fba7e6bbc5ff1794d71d8803f3f Mon Sep 17 00:00:00 2001 From: Ninos Date: Sun, 5 Nov 2023 05:14:24 +0100 Subject: [PATCH 21/31] [Validator] Renamed constants to full-word names --- .../Component/Validator/Constraints/Ip.php | 87 ++++++++++++++----- .../Validator/Constraints/IpValidator.php | 20 ++--- .../Tests/Constraints/IpValidatorTest.php | 20 ++--- 3 files changed, 83 insertions(+), 44 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/Ip.php b/src/Symfony/Component/Validator/Constraints/Ip.php index 7e8d8d448bb06..4c3f885179472 100644 --- a/src/Symfony/Component/Validator/Constraints/Ip.php +++ b/src/Symfony/Component/Validator/Constraints/Ip.php @@ -33,14 +33,14 @@ class Ip extends Constraint public const ALL = 'all'; // adds FILTER_FLAG_NO_PRIV_RANGE flag (skip private ranges) - public const V4_NO_PRIV = '4_no_priv'; - public const V6_NO_PRIV = '6_no_priv'; - public const ALL_NO_PRIV = 'all_no_priv'; + public const V4_NO_PRIVATE = '4_no_private'; + public const V6_NO_PRIVATE = '6_no_private'; + public const ALL_NO_PRIVATE = 'all_no_private'; // adds FILTER_FLAG_NO_RES_RANGE flag (skip reserved ranges) - public const V4_NO_RES = '4_no_res'; - public const V6_NO_RES = '6_no_res'; - public const ALL_NO_RES = 'all_no_res'; + public const V4_NO_RESERVED = '4_no_reserved'; + public const V6_NO_RESERVED = '6_no_reserved'; + public const ALL_NO_RESERVED = 'all_no_reserved'; // adds FILTER_FLAG_NO_PRIV_RANGE and FILTER_FLAG_NO_RES_RANGE flags (skip both) public const V4_ONLY_PUBLIC = '4_public'; @@ -48,41 +48,76 @@ class Ip extends Constraint public const ALL_ONLY_PUBLIC = 'all_public'; // adds inverse FILTER_FLAG_NO_PRIV_RANGE - public const V4_ONLY_PRIV = '4_priv'; - public const V6_ONLY_PRIV = '6_priv'; - public const ALL_ONLY_PRIV = 'all_priv'; + public const V4_ONLY_PRIVATE = '4_private'; + public const V6_ONLY_PRIVATE = '6_private'; + public const ALL_ONLY_PRIVATE = 'all_private'; // adds inverse FILTER_FLAG_NO_RES_RANGE - public const V4_ONLY_RES = '4_res'; - public const V6_ONLY_RES = '6_res'; - public const ALL_ONLY_RES = 'all_res'; + public const V4_ONLY_RESERVED = '4_reserved'; + public const V6_ONLY_RESERVED = '6_reserved'; + public const ALL_ONLY_RESERVED = 'all_reserved'; public const INVALID_IP_ERROR = 'b1b427ae-9f6f-41b0-aa9b-84511fbb3c5b'; + /** + * @deprecated since Symfony 6.4, use const V4_NO_PRIVATE instead + */ + public const V4_NO_PRIV = '4_no_priv'; + /** + * @deprecated since Symfony 6.4, use const V6_NO_PRIVATE instead + */ + public const V6_NO_PRIV = '6_no_priv'; + /** + * @deprecated since Symfony 6.4, use const ALL_NO_PRIVATE instead + */ + public const ALL_NO_PRIV = 'all_no_priv'; + /** + * @deprecated since Symfony 6.4, use const 4_NO_RESERVED instead + */ + public const V4_NO_RES = '4_no_res'; + /** + * @deprecated since Symfony 6.4, use const 6_NO_RESERVED instead + */ + public const V6_NO_RES = '6_no_res'; + /** + * @deprecated since Symfony 6.4, use const ALL_NO_RESERVED instead + */ + public const ALL_NO_RES = 'all_no_res'; + + protected const DEPRECATED_VERSIONS = [ + self::V4_NO_PRIV => self::V4_NO_PRIVATE, + self::V6_NO_PRIV => self::V6_NO_PRIVATE, + self::ALL_NO_PRIV => self::ALL_NO_PRIVATE, + + self::V4_NO_RES => self::V4_NO_RESERVED, + self::V6_NO_RES => self::V6_NO_RESERVED, + self::ALL_NO_RES => self::ALL_NO_RESERVED, + ]; + protected const VERSIONS = [ self::V4, self::V6, self::ALL, - self::V4_NO_PRIV, - self::V6_NO_PRIV, - self::ALL_NO_PRIV, + self::V4_NO_PRIVATE, + self::V6_NO_PRIVATE, + self::ALL_NO_PRIVATE, - self::V4_NO_RES, - self::V6_NO_RES, - self::ALL_NO_RES, + self::V4_NO_RESERVED, + self::V6_NO_RESERVED, + self::ALL_NO_RESERVED, self::V4_ONLY_PUBLIC, self::V6_ONLY_PUBLIC, self::ALL_ONLY_PUBLIC, - self::V4_ONLY_PRIV, - self::V6_ONLY_PRIV, - self::ALL_ONLY_PRIV, + self::V4_ONLY_PRIVATE, + self::V6_ONLY_PRIVATE, + self::ALL_ONLY_PRIVATE, - self::V4_ONLY_RES, - self::V6_ONLY_RES, - self::ALL_ONLY_RES, + self::V4_ONLY_RESERVED, + self::V6_ONLY_RESERVED, + self::ALL_ONLY_RESERVED, ]; protected const ERROR_NAMES = [ @@ -120,6 +155,10 @@ public function __construct( $this->message = $message ?? $this->message; $this->normalizer = $normalizer ?? $this->normalizer; + if (isset(self::DEPRECATED_VERSIONS[$this->version])) { + $this->version = self::DEPRECATED_VERSIONS[$this->version]; + } + if (!\in_array($this->version, self::$versions)) { throw new ConstraintDefinitionException(sprintf('The option "version" must be one of "%s".', implode('", "', self::$versions))); } diff --git a/src/Symfony/Component/Validator/Constraints/IpValidator.php b/src/Symfony/Component/Validator/Constraints/IpValidator.php index 3947721140ac8..212d2f15e54cf 100644 --- a/src/Symfony/Component/Validator/Constraints/IpValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IpValidator.php @@ -49,14 +49,14 @@ public function validate(mixed $value, Constraint $constraint) } $flag = match ($constraint->version) { - Ip::V4, Ip::V4_ONLY_PRIV, Ip::V4_ONLY_RES => \FILTER_FLAG_IPV4, - Ip::V6, Ip::V6_ONLY_PRIV, Ip::V6_ONLY_RES => \FILTER_FLAG_IPV6, - Ip::V4_NO_PRIV => \FILTER_FLAG_IPV4 | \FILTER_FLAG_NO_PRIV_RANGE, - Ip::V6_NO_PRIV => \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_PRIV_RANGE, - Ip::ALL_NO_PRIV => \FILTER_FLAG_NO_PRIV_RANGE, - Ip::V4_NO_RES => \FILTER_FLAG_IPV4 | \FILTER_FLAG_NO_RES_RANGE, - Ip::V6_NO_RES => \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_RES_RANGE, - Ip::ALL_NO_RES => \FILTER_FLAG_NO_RES_RANGE, + Ip::V4, Ip::V4_ONLY_PRIVATE, Ip::V4_ONLY_RESERVED => \FILTER_FLAG_IPV4, + Ip::V6, Ip::V6_ONLY_PRIVATE, Ip::V6_ONLY_RESERVED => \FILTER_FLAG_IPV6, + Ip::V4_NO_PRIVATE => \FILTER_FLAG_IPV4 | \FILTER_FLAG_NO_PRIV_RANGE, + Ip::V6_NO_PRIVATE => \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_PRIV_RANGE, + Ip::ALL_NO_PRIVATE => \FILTER_FLAG_NO_PRIV_RANGE, + Ip::V4_NO_RESERVED => \FILTER_FLAG_IPV4 | \FILTER_FLAG_NO_RES_RANGE, + Ip::V6_NO_RESERVED => \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_RES_RANGE, + Ip::ALL_NO_RESERVED => \FILTER_FLAG_NO_RES_RANGE, Ip::V4_ONLY_PUBLIC => \FILTER_FLAG_IPV4 | \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE, Ip::V6_ONLY_PUBLIC => \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE, Ip::ALL_ONLY_PUBLIC => \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE, @@ -73,8 +73,8 @@ public function validate(mixed $value, Constraint $constraint) } $inverseFlag = match ($constraint->version) { - Ip::V4_ONLY_PRIV, Ip::V6_ONLY_PRIV, Ip::ALL_ONLY_PRIV => \FILTER_FLAG_NO_PRIV_RANGE, - Ip::V4_ONLY_RES, Ip::V6_ONLY_RES, Ip::ALL_ONLY_RES => \FILTER_FLAG_NO_RES_RANGE, + Ip::V4_ONLY_PRIVATE, Ip::V6_ONLY_PRIVATE, Ip::ALL_ONLY_PRIVATE => \FILTER_FLAG_NO_PRIV_RANGE, + Ip::V4_ONLY_RESERVED, Ip::V6_ONLY_RESERVED, Ip::ALL_ONLY_RESERVED => \FILTER_FLAG_NO_RES_RANGE, default => 0, }; diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php index 4791e1c0d6acb..ed86ce970b04e 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php @@ -215,7 +215,7 @@ public static function getInvalidIpsV4() public function testValidPrivateIpsV4($ip) { $this->validator->validate($ip, new Ip([ - 'version' => Ip::V4_ONLY_PRIV, + 'version' => Ip::V4_ONLY_PRIVATE, ])); $this->assertNoViolation(); @@ -227,7 +227,7 @@ public function testValidPrivateIpsV4($ip) public function testInvalidPrivateIpsV4($ip) { $constraint = new Ip([ - 'version' => Ip::V4_NO_PRIV, + 'version' => Ip::V4_NO_PRIVATE, 'message' => 'myMessage', ]); @@ -245,7 +245,7 @@ public function testInvalidPrivateIpsV4($ip) public function testInvalidOnlyPrivateIpsV4($ip) { $constraint = new Ip([ - 'version' => Ip::V4_ONLY_PRIV, + 'version' => Ip::V4_ONLY_PRIVATE, 'message' => 'myMessage', ]); @@ -277,7 +277,7 @@ public static function getInvalidPrivateIpsV4() public function testValidReservedIpsV4($ip) { $this->validator->validate($ip, new Ip([ - 'version' => Ip::V4_ONLY_RES, + 'version' => Ip::V4_ONLY_RESERVED, ])); $this->assertNoViolation(); @@ -289,7 +289,7 @@ public function testValidReservedIpsV4($ip) public function testInvalidReservedIpsV4($ip) { $constraint = new Ip([ - 'version' => Ip::V4_NO_RES, + 'version' => Ip::V4_NO_RESERVED, 'message' => 'myMessage', ]); @@ -307,7 +307,7 @@ public function testInvalidReservedIpsV4($ip) public function testInvalidOnlyReservedIpsV4($ip) { $constraint = new Ip([ - 'version' => Ip::V4_ONLY_RES, + 'version' => Ip::V4_ONLY_RESERVED, 'message' => 'myMessage', ]); @@ -399,7 +399,7 @@ public static function getInvalidIpsV6() public function testInvalidPrivateIpsV6($ip) { $constraint = new Ip([ - 'version' => Ip::V6_NO_PRIV, + 'version' => Ip::V6_NO_PRIVATE, 'message' => 'myMessage', ]); @@ -426,7 +426,7 @@ public static function getInvalidPrivateIpsV6() public function testInvalidReservedIpsV6($ip) { $constraint = new Ip([ - 'version' => Ip::V6_NO_RES, + 'version' => Ip::V6_NO_RESERVED, 'message' => 'myMessage', ]); @@ -498,7 +498,7 @@ public static function getInvalidIpsAll() public function testInvalidPrivateIpsAll($ip) { $constraint = new Ip([ - 'version' => Ip::ALL_NO_PRIV, + 'version' => Ip::ALL_NO_PRIVATE, 'message' => 'myMessage', ]); @@ -521,7 +521,7 @@ public static function getInvalidPrivateIpsAll() public function testInvalidReservedIpsAll($ip) { $constraint = new Ip([ - 'version' => Ip::ALL_NO_RES, + 'version' => Ip::ALL_NO_RESERVED, 'message' => 'myMessage', ]); From 3f58f6b7288fe1e9e002bbcd017c2d6398e1ca51 Mon Sep 17 00:00:00 2001 From: Ninos Date: Sun, 5 Nov 2023 05:17:40 +0100 Subject: [PATCH 22/31] [Validator] Renamed constants to full-word names --- src/Symfony/Component/Validator/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 03939663fff12..75784fbd7a1ec 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 6.4 --- - * Add `*_ONLY_PRIV` and `*_ONLY_RES` versions to `Ip` constraint + * Add `*_ONLY_PRIVATE` and `*_ONLY_RESERVED` versions to `Ip` constraint * Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate` * Allow single integer for the `versions` option of the `Uuid` constraint * Allow single constraint to be passed to the `constraints` option of the `When` constraint From a0419db0f2ac330cc0c6bc399ef11070d8af413a Mon Sep 17 00:00:00 2001 From: Ninos Date: Mon, 6 Nov 2023 09:28:36 +0100 Subject: [PATCH 23/31] [Validator] Possibility to use all `Ip` constraint versions in `Cidr` constraint --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + .../Component/Validator/Constraints/Cidr.php | 22 +++++- .../Validator/Constraints/CidrValidator.php | 13 ++-- .../Validator/Constraints/IpValidator.php | 72 +++++++++++-------- 4 files changed, 69 insertions(+), 39 deletions(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 75784fbd7a1ec..c81b0207a6ccb 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add `*_ONLY_PRIVATE` and `*_ONLY_RESERVED` versions to `Ip` constraint + * Add `*_ONLY_PUBLIC`, `*_ONLY_PRIVATE` and `*_ONLY_RESERVED` versions to `Cidr` constraint * Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate` * Allow single integer for the `versions` option of the `Uuid` constraint * Allow single constraint to be passed to the `constraints` option of the `When` constraint diff --git a/src/Symfony/Component/Validator/Constraints/Cidr.php b/src/Symfony/Component/Validator/Constraints/Cidr.php index 03002a7b50aa3..9df19937c79c7 100644 --- a/src/Symfony/Component/Validator/Constraints/Cidr.php +++ b/src/Symfony/Component/Validator/Constraints/Cidr.php @@ -35,9 +35,29 @@ class Cidr extends Constraint ]; private const NET_MAXES = [ - Ip::ALL => 128, Ip::V4 => 32, Ip::V6 => 128, + Ip::ALL => 128, + + Ip::V4_NO_PRIVATE => 32, + Ip::V6_NO_PRIVATE => 128, + Ip::ALL_NO_PRIVATE => 128, + + Ip::V4_NO_RESERVED => 32, + Ip::V6_NO_RESERVED => 128, + Ip::ALL_NO_RESERVED => 128, + + Ip::V4_ONLY_PUBLIC => 32, + Ip::V6_ONLY_PUBLIC => 128, + Ip::ALL_ONLY_PUBLIC => 128, + + Ip::V4_ONLY_PRIVATE => 32, + Ip::V6_ONLY_PRIVATE => 128, + Ip::ALL_ONLY_PRIVATE => 128, + + Ip::V4_ONLY_RESERVED => 32, + Ip::V6_ONLY_RESERVED => 128, + Ip::ALL_ONLY_RESERVED => 128, ]; /** diff --git a/src/Symfony/Component/Validator/Constraints/CidrValidator.php b/src/Symfony/Component/Validator/Constraints/CidrValidator.php index c90ebcfae35f7..2b187d30433f3 100644 --- a/src/Symfony/Component/Validator/Constraints/CidrValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CidrValidator.php @@ -49,14 +49,7 @@ public function validate($value, Constraint $constraint): void $ipAddress = $cidrParts[0]; $netmask = (int) $cidrParts[1]; - $validV4 = Ip::V6 !== $constraint->version - && filter_var($ipAddress, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4) - && $netmask <= 32; - - $validV6 = Ip::V4 !== $constraint->version - && filter_var($ipAddress, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6); - - if (!$validV4 && !$validV6) { + if (!IpValidator::checkIP($ipAddress, $constraint->version)) { $this->context ->buildViolation($constraint->message) ->setCode(Cidr::INVALID_CIDR_ERROR) @@ -65,6 +58,10 @@ public function validate($value, Constraint $constraint): void return; } + if(filter_var($ipAddress, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4) && $constraint->netmaskMax > 32) { + $constraint->netmaskMax = 32; + } + if ($netmask < $constraint->netmaskMin || $netmask > $constraint->netmaskMax) { $this->context ->buildViolation($constraint->netmaskRangeViolationMessage) diff --git a/src/Symfony/Component/Validator/Constraints/IpValidator.php b/src/Symfony/Component/Validator/Constraints/IpValidator.php index 212d2f15e54cf..793996abe00f1 100644 --- a/src/Symfony/Component/Validator/Constraints/IpValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IpValidator.php @@ -25,30 +25,15 @@ */ class IpValidator extends ConstraintValidator { + /** - * @return void + * Checks whether an IP address is valid. + * + * @internal */ - public function validate(mixed $value, Constraint $constraint) + public static function checkIP(string $ip, mixed $version): bool { - if (!$constraint instanceof Ip) { - throw new UnexpectedTypeException($constraint, Ip::class); - } - - if (null === $value || '' === $value) { - return; - } - - if (!\is_scalar($value) && !$value instanceof \Stringable) { - throw new UnexpectedValueException($value, 'string'); - } - - $value = (string) $value; - - if (null !== $constraint->normalizer) { - $value = ($constraint->normalizer)($value); - } - - $flag = match ($constraint->version) { + $flag = match ($version) { Ip::V4, Ip::V4_ONLY_PRIVATE, Ip::V4_ONLY_RESERVED => \FILTER_FLAG_IPV4, Ip::V6, Ip::V6_ONLY_PRIVATE, Ip::V6_ONLY_RESERVED => \FILTER_FLAG_IPV6, Ip::V4_NO_PRIVATE => \FILTER_FLAG_IPV4 | \FILTER_FLAG_NO_PRIV_RANGE, @@ -63,26 +48,53 @@ public function validate(mixed $value, Constraint $constraint) default => 0, }; - if (!filter_var($value, \FILTER_VALIDATE_IP, $flag)) { - $this->context->buildViolation($constraint->message) - ->setParameter('{{ value }}', $this->formatValue($value)) - ->setCode(Ip::INVALID_IP_ERROR) - ->addViolation(); - - return; + if (!filter_var($ip, \FILTER_VALIDATE_IP, $flag)) { + return false; } - $inverseFlag = match ($constraint->version) { + $inverseFlag = match ($version) { Ip::V4_ONLY_PRIVATE, Ip::V6_ONLY_PRIVATE, Ip::ALL_ONLY_PRIVATE => \FILTER_FLAG_NO_PRIV_RANGE, Ip::V4_ONLY_RESERVED, Ip::V6_ONLY_RESERVED, Ip::ALL_ONLY_RESERVED => \FILTER_FLAG_NO_RES_RANGE, default => 0, }; - if ($inverseFlag && filter_var($value, \FILTER_VALIDATE_IP, $inverseFlag)) { + if ($inverseFlag && filter_var($ip, \FILTER_VALIDATE_IP, $inverseFlag)) { + return false; + } + + return true; + } + + /** + * @return void + */ + public function validate(mixed $value, Constraint $constraint) + { + if (!$constraint instanceof Ip) { + throw new UnexpectedTypeException($constraint, Ip::class); + } + + if (null === $value || '' === $value) { + return; + } + + if (!\is_scalar($value) && !$value instanceof \Stringable) { + throw new UnexpectedValueException($value, 'string'); + } + + $value = (string)$value; + + if (null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + + if(!self::checkIP($value, $constraint->version)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Ip::INVALID_IP_ERROR) ->addViolation(); + + return; } } } From ed09494b724cf30d9b59e171ebf271870e71dda2 Mon Sep 17 00:00:00 2001 From: Ninos Date: Mon, 6 Nov 2023 09:33:04 +0100 Subject: [PATCH 24/31] [Validator] Possibility to use all `Ip` constraint versions in `Cidr` constraint --- src/Symfony/Component/Validator/Constraints/Cidr.php | 1 + .../Component/Validator/Constraints/CidrValidator.php | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/Symfony/Component/Validator/Constraints/Cidr.php b/src/Symfony/Component/Validator/Constraints/Cidr.php index 9df19937c79c7..04351904bc4c5 100644 --- a/src/Symfony/Component/Validator/Constraints/Cidr.php +++ b/src/Symfony/Component/Validator/Constraints/Cidr.php @@ -22,6 +22,7 @@ * * @author Sorin Pop * @author Calin Bolea + * @author Ninos Ego */ #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class Cidr extends Constraint diff --git a/src/Symfony/Component/Validator/Constraints/CidrValidator.php b/src/Symfony/Component/Validator/Constraints/CidrValidator.php index 2b187d30433f3..131bb6c36e533 100644 --- a/src/Symfony/Component/Validator/Constraints/CidrValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CidrValidator.php @@ -16,6 +16,13 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\UnexpectedValueException; +/** + * Validates whether a value is a valid CIDR notation. + * + * @author Sorin Pop + * @author Calin Bolea + * @author Ninos Ego + */ class CidrValidator extends ConstraintValidator { public function validate($value, Constraint $constraint): void From 65b318457bfd2df17ff71387c9310e4fa5eb2d47 Mon Sep 17 00:00:00 2001 From: Ninos Date: Mon, 6 Nov 2023 09:37:25 +0100 Subject: [PATCH 25/31] [Validator] Possibility to use all `Ip` constraint versions in `Cidr` constraint --- src/Symfony/Component/Validator/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index c81b0207a6ccb..33677f14e7f47 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -5,7 +5,7 @@ CHANGELOG --- * Add `*_ONLY_PRIVATE` and `*_ONLY_RESERVED` versions to `Ip` constraint - * Add `*_ONLY_PUBLIC`, `*_ONLY_PRIVATE` and `*_ONLY_RESERVED` versions to `Cidr` constraint + * Possibility to use all `Ip` constraint versions for `Cidr` constraint * Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate` * Allow single integer for the `versions` option of the `Uuid` constraint * Allow single constraint to be passed to the `constraints` option of the `When` constraint From b0660877d294f8311a3f2a8446e2ec419bf836e2 Mon Sep 17 00:00:00 2001 From: Ninos Date: Mon, 6 Nov 2023 12:42:32 +0100 Subject: [PATCH 26/31] [Validator] Possibility to use all `Ip` constraint versions in `Cidr` constraint --- src/Symfony/Component/Validator/Constraints/CidrValidator.php | 2 +- src/Symfony/Component/Validator/Constraints/IpValidator.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/CidrValidator.php b/src/Symfony/Component/Validator/Constraints/CidrValidator.php index 131bb6c36e533..43b26158ff57c 100644 --- a/src/Symfony/Component/Validator/Constraints/CidrValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CidrValidator.php @@ -56,7 +56,7 @@ public function validate($value, Constraint $constraint): void $ipAddress = $cidrParts[0]; $netmask = (int) $cidrParts[1]; - if (!IpValidator::checkIP($ipAddress, $constraint->version)) { + if (!IpValidator::checkIp($ipAddress, $constraint->version)) { $this->context ->buildViolation($constraint->message) ->setCode(Cidr::INVALID_CIDR_ERROR) diff --git a/src/Symfony/Component/Validator/Constraints/IpValidator.php b/src/Symfony/Component/Validator/Constraints/IpValidator.php index 793996abe00f1..cc70e1780821d 100644 --- a/src/Symfony/Component/Validator/Constraints/IpValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IpValidator.php @@ -31,7 +31,7 @@ class IpValidator extends ConstraintValidator * * @internal */ - public static function checkIP(string $ip, mixed $version): bool + public static function checkIp(string $ip, mixed $version): bool { $flag = match ($version) { Ip::V4, Ip::V4_ONLY_PRIVATE, Ip::V4_ONLY_RESERVED => \FILTER_FLAG_IPV4, @@ -88,7 +88,7 @@ public function validate(mixed $value, Constraint $constraint) $value = ($constraint->normalizer)($value); } - if(!self::checkIP($value, $constraint->version)) { + if(!self::checkIp($value, $constraint->version)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Ip::INVALID_IP_ERROR) From 1991107a136627e3d68ec7a72efa43b92c944ebd Mon Sep 17 00:00:00 2001 From: Ninos Date: Mon, 6 Nov 2023 13:06:41 +0100 Subject: [PATCH 27/31] [Validator] Fixed tests & added `*_NO_PUBLIC` --- src/Symfony/Component/Validator/CHANGELOG.md | 2 +- .../Component/Validator/Constraints/Cidr.php | 4 ++++ .../Component/Validator/Constraints/Ip.php | 9 +++++++++ .../Validator/Constraints/IpValidator.php | 5 +++-- .../Validator/Tests/Constraints/CidrTest.php | 10 +++++++++- .../Tests/Constraints/CidrValidatorTest.php | 2 +- .../Tests/Constraints/IpValidatorTest.php | 18 ++++++++++++++++++ 7 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 33677f14e7f47..c698979cd2134 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 6.4 --- - * Add `*_ONLY_PRIVATE` and `*_ONLY_RESERVED` versions to `Ip` constraint + * Add `*_NO_PUBLIC`, `*_ONLY_PRIVATE` and `*_ONLY_RESERVED` versions to `Ip` constraint * Possibility to use all `Ip` constraint versions for `Cidr` constraint * Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate` * Allow single integer for the `versions` option of the `Uuid` constraint diff --git a/src/Symfony/Component/Validator/Constraints/Cidr.php b/src/Symfony/Component/Validator/Constraints/Cidr.php index 04351904bc4c5..6f5036f9965f8 100644 --- a/src/Symfony/Component/Validator/Constraints/Cidr.php +++ b/src/Symfony/Component/Validator/Constraints/Cidr.php @@ -40,6 +40,10 @@ class Cidr extends Constraint Ip::V6 => 128, Ip::ALL => 128, + Ip::V4_NO_PUBLIC => 32, + Ip::V6_NO_PUBLIC => 128, + Ip::ALL_NO_PUBLIC => 128, + Ip::V4_NO_PRIVATE => 32, Ip::V6_NO_PRIVATE => 128, Ip::ALL_NO_PRIVATE => 128, diff --git a/src/Symfony/Component/Validator/Constraints/Ip.php b/src/Symfony/Component/Validator/Constraints/Ip.php index 4c3f885179472..d3a60260f0d12 100644 --- a/src/Symfony/Component/Validator/Constraints/Ip.php +++ b/src/Symfony/Component/Validator/Constraints/Ip.php @@ -32,6 +32,11 @@ class Ip extends Constraint public const V6 = '6'; public const ALL = 'all'; + // adds inverse FILTER_FLAG_NO_RES_RANGE and FILTER_FLAG_NO_PRIV_RANGE flags (skip both) + public const V4_NO_PUBLIC = '4_no_public'; + public const V6_NO_PUBLIC = '6_no_public'; + public const ALL_NO_PUBLIC = 'all_no_public'; + // adds FILTER_FLAG_NO_PRIV_RANGE flag (skip private ranges) public const V4_NO_PRIVATE = '4_no_private'; public const V6_NO_PRIVATE = '6_no_private'; @@ -99,6 +104,10 @@ class Ip extends Constraint self::V6, self::ALL, + self::V4_NO_PUBLIC, + self::V6_NO_PUBLIC, + self::ALL_NO_PUBLIC, + self::V4_NO_PRIVATE, self::V6_NO_PRIVATE, self::ALL_NO_PRIVATE, diff --git a/src/Symfony/Component/Validator/Constraints/IpValidator.php b/src/Symfony/Component/Validator/Constraints/IpValidator.php index cc70e1780821d..855a3a3844236 100644 --- a/src/Symfony/Component/Validator/Constraints/IpValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IpValidator.php @@ -34,8 +34,8 @@ class IpValidator extends ConstraintValidator public static function checkIp(string $ip, mixed $version): bool { $flag = match ($version) { - Ip::V4, Ip::V4_ONLY_PRIVATE, Ip::V4_ONLY_RESERVED => \FILTER_FLAG_IPV4, - Ip::V6, Ip::V6_ONLY_PRIVATE, Ip::V6_ONLY_RESERVED => \FILTER_FLAG_IPV6, + Ip::V4, Ip::V4_NO_PUBLIC, Ip::V4_ONLY_PRIVATE, Ip::V4_ONLY_RESERVED => \FILTER_FLAG_IPV4, + Ip::V6, Ip::V6_NO_PUBLIC, Ip::V6_ONLY_PRIVATE, Ip::V6_ONLY_RESERVED => \FILTER_FLAG_IPV6, Ip::V4_NO_PRIVATE => \FILTER_FLAG_IPV4 | \FILTER_FLAG_NO_PRIV_RANGE, Ip::V6_NO_PRIVATE => \FILTER_FLAG_IPV6 | \FILTER_FLAG_NO_PRIV_RANGE, Ip::ALL_NO_PRIVATE => \FILTER_FLAG_NO_PRIV_RANGE, @@ -53,6 +53,7 @@ public static function checkIp(string $ip, mixed $version): bool } $inverseFlag = match ($version) { + Ip::V4_NO_PUBLIC, Ip::V6_NO_PUBLIC, Ip::ALL_NO_PUBLIC => \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE, Ip::V4_ONLY_PRIVATE, Ip::V6_ONLY_PRIVATE, Ip::ALL_ONLY_PRIVATE => \FILTER_FLAG_NO_PRIV_RANGE, Ip::V4_ONLY_RESERVED, Ip::V6_ONLY_RESERVED, Ip::ALL_ONLY_RESERVED => \FILTER_FLAG_NO_RES_RANGE, default => 0, diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CidrTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CidrTest.php index c9239de4d2a5b..bf7e6349aa72b 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CidrTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CidrTest.php @@ -49,7 +49,15 @@ public function testForV6() public function testWithInvalidVersion() { - $availableVersions = [Ip::ALL, Ip::V4, Ip::V6]; + $availableVersions = [ + Ip::V4, Ip::V6, Ip::ALL, + Ip::V4_NO_PUBLIC, Ip::V6_NO_PUBLIC, Ip::ALL_NO_PUBLIC, + Ip::V4_NO_PRIVATE, Ip::V6_NO_PRIVATE, Ip::ALL_NO_PRIVATE, + Ip::V4_NO_RESERVED, Ip::V6_NO_RESERVED, Ip::ALL_NO_RESERVED, + Ip::V4_ONLY_PUBLIC, Ip::V6_ONLY_PUBLIC, Ip::ALL_ONLY_PUBLIC, + Ip::V4_ONLY_PRIVATE, Ip::V6_ONLY_PRIVATE, Ip::ALL_ONLY_PRIVATE, + Ip::V4_ONLY_RESERVED, Ip::V6_ONLY_RESERVED, Ip::ALL_ONLY_RESERVED + ]; self::expectException(ConstraintDefinitionException::class); self::expectExceptionMessage(sprintf('The option "version" must be one of "%s".', implode('", "', $availableVersions))); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CidrValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CidrValidatorTest.php index 7c5745ee6942a..69098bfbfd182 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CidrValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CidrValidatorTest.php @@ -221,7 +221,6 @@ public static function getWithInvalidMasksAndIps(): array { return [ ['0.0.0.0/foobar'], - ['10.0.0.0/128'], ['123.45.67.178/aaa'], ['172.16.0.0//'], ['172.16.0.0/a/'], @@ -240,6 +239,7 @@ public static function getOutOfRangeNetmask(): array { return [ ['10.0.0.0/24', Ip::V4, 10, 20], + ['10.0.0.0/128'], ['2001:0DB8:85A3:0000:0000:8A2E:0370:7334/24', Ip::V6, 10, 20], ]; } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php index ed86ce970b04e..ea24d811163d2 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php @@ -185,6 +185,24 @@ public function testInvalidIpsV4($ip) ->assertRaised(); } + /** + * @dataProvider getValidIpsV4 + */ + public function testInvalidNoPublicIpsV4($ip) + { + $constraint = new Ip([ + 'version' => Ip::V4_NO_PUBLIC, + 'message' => 'myMessage', + ]); + + $this->validator->validate($ip, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '"'.$ip.'"') + ->setCode(Ip::INVALID_IP_ERROR) + ->assertRaised(); + } + public static function getValidPublicIpsV4() { return [ From cbdd81f7b0faae39c4e9d279180128576535dda7 Mon Sep 17 00:00:00 2001 From: Ninos Date: Mon, 6 Nov 2023 13:17:26 +0100 Subject: [PATCH 28/31] [Validator] Fixed tests --- .../Component/Validator/Tests/Constraints/CidrValidatorTest.php | 1 - .../Component/Validator/Tests/Constraints/IpValidatorTest.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CidrValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CidrValidatorTest.php index 69098bfbfd182..b95e98132b4ec 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CidrValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CidrValidatorTest.php @@ -203,7 +203,6 @@ public static function getWithInvalidNetmask(): array return [ ['192.168.1.0/-1'], ['0.0.0.0/foobar'], - ['10.0.0.0/128'], ['123.45.67.178/aaa'], ['172.16.0.0//'], ['255.255.255.255/1/4'], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php index ea24d811163d2..a2277a3d8ff86 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php @@ -186,7 +186,7 @@ public function testInvalidIpsV4($ip) } /** - * @dataProvider getValidIpsV4 + * @dataProvider getValidPublicIpsV4 */ public function testInvalidNoPublicIpsV4($ip) { From 601809c5f9e2514ce37ce1b4e43d02939560e4bf Mon Sep 17 00:00:00 2001 From: Ninos Date: Tue, 7 Nov 2023 11:45:06 +0100 Subject: [PATCH 29/31] [Validator] Added normalizer to `Cidr` + better string support --- .../Component/Validator/Constraints/Cidr.php | 17 +++++++++++------ .../Validator/Constraints/CidrValidator.php | 17 ++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/Cidr.php b/src/Symfony/Component/Validator/Constraints/Cidr.php index 6f5036f9965f8..625599c68599b 100644 --- a/src/Symfony/Component/Validator/Constraints/Cidr.php +++ b/src/Symfony/Component/Validator/Constraints/Cidr.php @@ -13,6 +13,7 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; +use Symfony\Component\Validator\Exception\InvalidArgumentException; /** * Validates that a value is a valid CIDR notation. @@ -22,7 +23,6 @@ * * @author Sorin Pop * @author Calin Bolea - * @author Ninos Ego */ #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class Cidr extends Constraint @@ -40,10 +40,6 @@ class Cidr extends Constraint Ip::V6 => 128, Ip::ALL => 128, - Ip::V4_NO_PUBLIC => 32, - Ip::V6_NO_PUBLIC => 128, - Ip::ALL_NO_PUBLIC => 128, - Ip::V4_NO_PRIVATE => 32, Ip::V6_NO_PRIVATE => 128, Ip::ALL_NO_PRIVATE => 128, @@ -80,24 +76,29 @@ class Cidr extends Constraint public $netmaskMax; + /** @var callable|null */ + public $normalizer; + public function __construct( array $options = null, string $version = null, int $netmaskMin = null, int $netmaskMax = null, string $message = null, + callable $normalizer = null, array $groups = null, $payload = null ) { $this->version = $version ?? $options['version'] ?? $this->version; - if (!\array_key_exists($this->version, self::NET_MAXES)) { + if (!\in_array($this->version, array_keys(self::NET_MAXES))) { throw new ConstraintDefinitionException(sprintf('The option "version" must be one of "%s".', implode('", "', array_keys(self::NET_MAXES)))); } $this->netmaskMin = $netmaskMin ?? $options['netmaskMin'] ?? $this->netmaskMin; $this->netmaskMax = $netmaskMax ?? $options['netmaskMax'] ?? self::NET_MAXES[$this->version]; $this->message = $message ?? $this->message; + $this->normalizer = $normalizer ?? $this->normalizer; unset($options['netmaskMin'], $options['netmaskMax'], $options['version']); @@ -105,6 +106,10 @@ public function __construct( throw new ConstraintDefinitionException(sprintf('The netmask range must be between 0 and %d.', self::NET_MAXES[$this->version])); } + if (null !== $this->normalizer && !\is_callable($this->normalizer)) { + throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', get_debug_type($this->normalizer))); + } + parent::__construct($options, $groups, $payload); } } diff --git a/src/Symfony/Component/Validator/Constraints/CidrValidator.php b/src/Symfony/Component/Validator/Constraints/CidrValidator.php index 43b26158ff57c..6ac8b4c860184 100644 --- a/src/Symfony/Component/Validator/Constraints/CidrValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CidrValidator.php @@ -16,13 +16,6 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\UnexpectedValueException; -/** - * Validates whether a value is a valid CIDR notation. - * - * @author Sorin Pop - * @author Calin Bolea - * @author Ninos Ego - */ class CidrValidator extends ConstraintValidator { public function validate($value, Constraint $constraint): void @@ -35,10 +28,16 @@ public function validate($value, Constraint $constraint): void return; } - if (!\is_string($value)) { + if (!\is_scalar($value) && !$value instanceof \Stringable) { throw new UnexpectedValueException($value, 'string'); } + $value = (string)$value; + + if (null !== $constraint->normalizer) { + $value = ($constraint->normalizer)($value); + } + $cidrParts = explode('/', $value, 2); if (!isset($cidrParts[1]) @@ -56,7 +55,7 @@ public function validate($value, Constraint $constraint): void $ipAddress = $cidrParts[0]; $netmask = (int) $cidrParts[1]; - if (!IpValidator::checkIp($ipAddress, $constraint->version)) { + if (!IpValidator::checkIP($ipAddress, $constraint->version)) { $this->context ->buildViolation($constraint->message) ->setCode(Cidr::INVALID_CIDR_ERROR) From 0d12319cd3faea080cc1b4d78a79514ec2ce12af Mon Sep 17 00:00:00 2001 From: Ninos Date: Mon, 20 Nov 2023 17:49:39 +0100 Subject: [PATCH 30/31] [Validator] Small fixes --- src/Symfony/Component/Validator/CHANGELOG.md | 8 ++++-- .../Component/Validator/Constraints/Cidr.php | 14 +++++------ .../Component/Validator/Constraints/Ip.php | 25 +++---------------- .../Validator/Constraints/IpValidator.php | 2 +- 4 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index aea6ed3e6341d..a15d868334be9 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -19,11 +19,15 @@ CHANGELOG * Remove `ValidatorBuilder::disableAnnotationMapping()`, use `ValidatorBuilder::disableAttributeMapping()` instead * Remove `AnnotationLoader`, use `AttributeLoader` instead +7.1 +--- + +* Add `*_NO_PUBLIC`, `*_ONLY_PRIVATE` and `*_ONLY_RESERVED` versions to `Ip` constraint +* Possibility to use all `Ip` constraint versions for `Cidr` constraint + 6.4 --- - * Add `*_NO_PUBLIC`, `*_ONLY_PRIVATE` and `*_ONLY_RESERVED` versions to `Ip` constraint - * Possibility to use all `Ip` constraint versions for `Cidr` constraint * Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate` * Allow single integer for the `versions` option of the `Uuid` constraint * Allow single constraint to be passed to the `constraints` option of the `When` constraint diff --git a/src/Symfony/Component/Validator/Constraints/Cidr.php b/src/Symfony/Component/Validator/Constraints/Cidr.php index a89ac960ee825..5096715b860ff 100644 --- a/src/Symfony/Component/Validator/Constraints/Cidr.php +++ b/src/Symfony/Component/Validator/Constraints/Cidr.php @@ -73,25 +73,25 @@ public function __construct( int $netmaskMin = null, int $netmaskMax = null, string $message = null, - callable $normalizer = null, array $groups = null, - $payload = null + $payload = null, + callable $normalizer = null ) { $this->version = $version ?? $options['version'] ?? $this->version; - if (!\in_array($this->version, array_keys(self::NET_MAXES))) { - throw new ConstraintDefinitionException(sprintf('The option "version" must be one of "%s".', implode('", "', array_keys(self::NET_MAXES)))); + if (!\array_key_exists($this->version, self::NET_MAXES)) { + throw new ConstraintDefinitionException(sprintf('The option "version" must be one of "%s".', implode('", "', array_keys(static::NET_MAXES)))); } $this->netmaskMin = $netmaskMin ?? $options['netmaskMin'] ?? $this->netmaskMin; - $this->netmaskMax = $netmaskMax ?? $options['netmaskMax'] ?? self::NET_MAXES[$this->version]; + $this->netmaskMax = $netmaskMax ?? $options['netmaskMax'] ?? static::NET_MAXES[$this->version]; $this->message = $message ?? $this->message; $this->normalizer = $normalizer ?? $this->normalizer; unset($options['netmaskMin'], $options['netmaskMax'], $options['version']); - if ($this->netmaskMin < 0 || $this->netmaskMax > self::NET_MAXES[$this->version] || $this->netmaskMin > $this->netmaskMax) { - throw new ConstraintDefinitionException(sprintf('The netmask range must be between 0 and %d.', self::NET_MAXES[$this->version])); + if ($this->netmaskMin < 0 || $this->netmaskMax > static::NET_MAXES[$this->version] || $this->netmaskMin > $this->netmaskMax) { + throw new ConstraintDefinitionException(sprintf('The netmask range must be between 0 and %d.', static::NET_MAXES[$this->version])); } if (null !== $this->normalizer && !\is_callable($this->normalizer)) { diff --git a/src/Symfony/Component/Validator/Constraints/Ip.php b/src/Symfony/Component/Validator/Constraints/Ip.php index 806bfe2cf3161..da046160b334f 100644 --- a/src/Symfony/Component/Validator/Constraints/Ip.php +++ b/src/Symfony/Component/Validator/Constraints/Ip.php @@ -61,32 +61,15 @@ class Ip extends Constraint public const INVALID_IP_ERROR = 'b1b427ae-9f6f-41b0-aa9b-84511fbb3c5b'; - /** - * @deprecated since Symfony 6.4, use const V4_NO_PRIVATE instead - */ + // BC: Aliases public const V4_NO_PRIV = '4_no_priv'; - /** - * @deprecated since Symfony 6.4, use const V6_NO_PRIVATE instead - */ public const V6_NO_PRIV = '6_no_priv'; - /** - * @deprecated since Symfony 6.4, use const ALL_NO_PRIVATE instead - */ public const ALL_NO_PRIV = 'all_no_priv'; - /** - * @deprecated since Symfony 6.4, use const 4_NO_RESERVED instead - */ public const V4_NO_RES = '4_no_res'; - /** - * @deprecated since Symfony 6.4, use const 6_NO_RESERVED instead - */ public const V6_NO_RES = '6_no_res'; - /** - * @deprecated since Symfony 6.4, use const ALL_NO_RESERVED instead - */ public const ALL_NO_RES = 'all_no_res'; - protected const DEPRECATED_VERSIONS = [ + protected const ALIAS_VERSIONS = [ self::V4_NO_PRIV => self::V4_NO_PRIVATE, self::V6_NO_PRIV => self::V6_NO_PRIVATE, self::ALL_NO_PRIV => self::ALL_NO_PRIVATE, @@ -149,8 +132,8 @@ public function __construct( $this->message = $message ?? $this->message; $this->normalizer = $normalizer ?? $this->normalizer; - if (isset(self::DEPRECATED_VERSIONS[$this->version])) { - $this->version = self::DEPRECATED_VERSIONS[$this->version]; + if (isset(static::ALIAS_VERSIONS[$this->version])) { + $this->version = static::ALIAS_VERSIONS[$this->version]; } if (!\in_array($this->version, static::VERSIONS, true)) { diff --git a/src/Symfony/Component/Validator/Constraints/IpValidator.php b/src/Symfony/Component/Validator/Constraints/IpValidator.php index 608846b5139e6..1845b242cad0f 100644 --- a/src/Symfony/Component/Validator/Constraints/IpValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IpValidator.php @@ -82,7 +82,7 @@ public function validate(mixed $value, Constraint $constraint): void throw new UnexpectedValueException($value, 'string'); } - $value = (string)$value; + $value = (string) $value; if (null !== $constraint->normalizer) { $value = ($constraint->normalizer)($value); From b58bb034cc9682f5ff84ed4f183cba7aa7dcccbc Mon Sep 17 00:00:00 2001 From: Ninos Date: Mon, 20 Nov 2023 17:50:10 +0100 Subject: [PATCH 31/31] [Validator] Small fixes --- src/Symfony/Component/Validator/Constraints/CidrValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/CidrValidator.php b/src/Symfony/Component/Validator/Constraints/CidrValidator.php index 6ac8b4c860184..d5a7d43862672 100644 --- a/src/Symfony/Component/Validator/Constraints/CidrValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CidrValidator.php @@ -32,7 +32,7 @@ public function validate($value, Constraint $constraint): void throw new UnexpectedValueException($value, 'string'); } - $value = (string)$value; + $value = (string) $value; if (null !== $constraint->normalizer) { $value = ($constraint->normalizer)($value);