From 4ce65d59ca91871cfd126497158200a818720bce Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 13:30:08 +0200 Subject: Adding upstream version 0.13.1. Signed-off-by: Daniel Baumann --- vendor/ipl/validator/LICENSE | 21 ++ vendor/ipl/validator/composer.json | 28 ++ vendor/ipl/validator/src/BaseValidator.php | 11 + vendor/ipl/validator/src/BetweenValidator.php | 159 ++++++++++ vendor/ipl/validator/src/CallbackValidator.php | 45 +++ vendor/ipl/validator/src/CidrValidator.php | 60 ++++ vendor/ipl/validator/src/DateTimeValidator.php | 65 ++++ .../ipl/validator/src/DeferredInArrayValidator.php | 55 ++++ vendor/ipl/validator/src/EmailAddressValidator.php | 341 +++++++++++++++++++++ vendor/ipl/validator/src/FileValidator.php | 248 +++++++++++++++ vendor/ipl/validator/src/GreaterThanValidator.php | 69 +++++ vendor/ipl/validator/src/HexColorValidator.php | 37 +++ vendor/ipl/validator/src/HostnameValidator.php | 37 +++ vendor/ipl/validator/src/InArrayValidator.php | 128 ++++++++ vendor/ipl/validator/src/LessThanValidator.php | 69 +++++ vendor/ipl/validator/src/PrivateKeyValidator.php | 33 ++ vendor/ipl/validator/src/StringLengthValidator.php | 179 +++++++++++ vendor/ipl/validator/src/ValidatorChain.php | 284 +++++++++++++++++ vendor/ipl/validator/src/X509CertValidator.php | 33 ++ 19 files changed, 1902 insertions(+) create mode 100644 vendor/ipl/validator/LICENSE create mode 100644 vendor/ipl/validator/composer.json create mode 100644 vendor/ipl/validator/src/BaseValidator.php create mode 100644 vendor/ipl/validator/src/BetweenValidator.php create mode 100644 vendor/ipl/validator/src/CallbackValidator.php create mode 100644 vendor/ipl/validator/src/CidrValidator.php create mode 100644 vendor/ipl/validator/src/DateTimeValidator.php create mode 100644 vendor/ipl/validator/src/DeferredInArrayValidator.php create mode 100644 vendor/ipl/validator/src/EmailAddressValidator.php create mode 100644 vendor/ipl/validator/src/FileValidator.php create mode 100644 vendor/ipl/validator/src/GreaterThanValidator.php create mode 100644 vendor/ipl/validator/src/HexColorValidator.php create mode 100644 vendor/ipl/validator/src/HostnameValidator.php create mode 100644 vendor/ipl/validator/src/InArrayValidator.php create mode 100644 vendor/ipl/validator/src/LessThanValidator.php create mode 100644 vendor/ipl/validator/src/PrivateKeyValidator.php create mode 100644 vendor/ipl/validator/src/StringLengthValidator.php create mode 100644 vendor/ipl/validator/src/ValidatorChain.php create mode 100644 vendor/ipl/validator/src/X509CertValidator.php (limited to 'vendor/ipl/validator') diff --git a/vendor/ipl/validator/LICENSE b/vendor/ipl/validator/LICENSE new file mode 100644 index 0000000..b247ccf --- /dev/null +++ b/vendor/ipl/validator/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2020 Icinga GmbH https://www.icinga.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/ipl/validator/composer.json b/vendor/ipl/validator/composer.json new file mode 100644 index 0000000..51ba68d --- /dev/null +++ b/vendor/ipl/validator/composer.json @@ -0,0 +1,28 @@ +{ + "name": "ipl/validator", + "type": "library", + "description": "Icinga PHP Library - Common validators and validator chaining", + "homepage": "https://github.com/Icinga/ipl-validator", + "license": "MIT", + "require": { + "php": ">=7.2", + "ext-mbstring": "*", + "ext-openssl": "*", + "ipl/stdlib": ">=0.12.0", + "ipl/i18n": ">=0.2.0", + "psr/http-message": "~1.0" + }, + "autoload": { + "psr-4": { + "ipl\\Validator\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "ipl\\Tests\\Validator\\": "tests" + } + }, + "require-dev": { + "guzzlehttp/psr7": "^1" + } +} diff --git a/vendor/ipl/validator/src/BaseValidator.php b/vendor/ipl/validator/src/BaseValidator.php new file mode 100644 index 0000000..8faa79b --- /dev/null +++ b/vendor/ipl/validator/src/BaseValidator.php @@ -0,0 +1,11 @@ +setMin($options['min']) + ->setMax($options['max']) + ->setInclusive($options['inclusive'] ?? true); + } + + /** + * Return the min option + * + * @return mixed + */ + public function getMin() + { + return $this->min; + } + + /** + * Set the min option + * + * @param mixed $min + * + * @return $this + */ + public function setMin($min): self + { + $this->min = $min; + + return $this; + } + + /** + * Return the max option + * + * @return mixed + */ + public function getMax() + { + return $this->max; + } + + /** + * Set the max option + * + * @param mixed $max + * + * @return $this + */ + public function setMax($max): self + { + $this->max = $max; + + return $this; + } + + /** + * Return the inclusive option + * + * @return bool + */ + public function getInclusive(): bool + { + return $this->inclusive; + } + + /** + * Set the inclusive option + * + * @param bool $inclusive + * + * @return $this + */ + public function setInclusive($inclusive = true): self + { + $this->inclusive = (bool) $inclusive; + + return $this; + } + + public function isValid($value) + { + // Multiple isValid() calls must not stack validation messages + $this->clearMessages(); + + if ($this->getInclusive()) { + if ($this->getMin() > $value || $value > $this->getMax()) { + $this->addMessage(sprintf( + $this->translate("'%s' is not between '%s' and '%s', inclusively"), + $value, + $this->getMin(), + $this->getMax() + )); + + return false; + } + } elseif ($this->getMin() >= $value || $value >= $this->getMax()) { + $this->addMessage(sprintf( + $this->translate("'%s' is not between '%s' and '%s'"), + $value, + $this->getMin(), + $this->getMax() + )); + + return false; + } + + return true; + } +} diff --git a/vendor/ipl/validator/src/CallbackValidator.php b/vendor/ipl/validator/src/CallbackValidator.php new file mode 100644 index 0000000..611a45e --- /dev/null +++ b/vendor/ipl/validator/src/CallbackValidator.php @@ -0,0 +1,45 @@ +addMessage('Record already exists in database'); + * + * return false; + * } + * + * return true; + * }); + * + * $dedup->isValid($id); + * ``` + */ +class CallbackValidator extends BaseValidator +{ + /** @var callable Validation callback */ + protected $callback; + + /** + * Create a new callback validator + * + * @param callable $callback Validation callback + */ + public function __construct(callable $callback) + { + $this->callback = $callback; + } + + public function isValid($value) + { + // Multiple isValid() calls must not stack validation messages + $this->clearMessages(); + + return call_user_func($this->callback, $value, $this); + } +} diff --git a/vendor/ipl/validator/src/CidrValidator.php b/vendor/ipl/validator/src/CidrValidator.php new file mode 100644 index 0000000..32c1162 --- /dev/null +++ b/vendor/ipl/validator/src/CidrValidator.php @@ -0,0 +1,60 @@ +clearMessages(); + + $pieces = Str::trimSplit($value, '/'); + if (count($pieces) !== 2) { + $this->addMessage(sprintf( + $this->translate('CIDR "%s" does not conform to the required format $address/$prefix'), + $value + )); + + return false; + } + + list($address, $prefix) = $pieces; + $inaddr = @inet_pton($address); + if ($inaddr === false) { + $this->addMessage(sprintf($this->translate('CIDR "%s" contains an invalid address'), $value)); + + return false; + } + + if (! is_numeric($prefix)) { + $this->addMessage(sprintf($this->translate('Prefix of CIDR "%s" must be a number'), $value)); + + return false; + } + + $isIPv6 = isset($inaddr[4]); + $prefix = (int) $prefix; + $maxPrefixLength = $isIPv6 ? 128 : 32; + + if ($prefix < 0 || $prefix > $maxPrefixLength) { + $this->addMessage(sprintf( + $this->translate('Prefix length of CIDR "%s" must be between 0 and %d for IPv%d addresses'), + $value, + $maxPrefixLength, + $isIPv6 ? 6 : 4 + )); + + return false; + } + + return true; + } +} diff --git a/vendor/ipl/validator/src/DateTimeValidator.php b/vendor/ipl/validator/src/DateTimeValidator.php new file mode 100644 index 0000000..1e35d61 --- /dev/null +++ b/vendor/ipl/validator/src/DateTimeValidator.php @@ -0,0 +1,65 @@ +local = (bool) $local; + } + + /** + * Check whether the given date time is valid + * + * @param string|DateTime $value + * + * @return bool + */ + public function isValid($value) + { + // Multiple isValid() calls must not stack validation messages + $this->clearMessages(); + + if (! $value instanceof DateTime && ! is_string($value)) { + $this->addMessage($this->translate('Invalid date/time given.')); + + return false; + } + + if (! $value instanceof DateTime) { + $format = $this->local === true ? static::FORMAT : DateTime::RFC3339; + $dateTime = DateTime::createFromFormat($format, $value); + + if ($dateTime === false || $dateTime->format($format) !== $value) { + $this->addMessage(sprintf( + $this->translate("Date/time string not in the expected format: %s"), + $format + )); + + return false; + } + } + + return true; + } +} diff --git a/vendor/ipl/validator/src/DeferredInArrayValidator.php b/vendor/ipl/validator/src/DeferredInArrayValidator.php new file mode 100644 index 0000000..55b9b83 --- /dev/null +++ b/vendor/ipl/validator/src/DeferredInArrayValidator.php @@ -0,0 +1,55 @@ +callback = $callback; + + parent::__construct($options); + } + + public function getHaystack(): array + { + return $this->haystack ?? call_user_func($this->callback); + } + + /** + * Set the callback + * + * @param callable $callback + * + * @return $this + */ + public function setCallback(callable $callback): self + { + $this->haystack = null; + $this->callback = $callback; + + return $this; + } +} diff --git a/vendor/ipl/validator/src/EmailAddressValidator.php b/vendor/ipl/validator/src/EmailAddressValidator.php new file mode 100644 index 0000000..52c3697 --- /dev/null +++ b/vendor/ipl/validator/src/EmailAddressValidator.php @@ -0,0 +1,341 @@ +@) + * + * We currently do not support dot-atom syntax (refer RFC 2822 [https://www.ietf.org/rfc/rfc2822.txt] + * documentation for more details) for domain-literal part of an email address + * + */ +class EmailAddressValidator extends BaseValidator +{ + use Translation; + + /** + * If MX check should be enabled + * + * @var bool + */ + protected $mx = false; + + /** + * If a deep MX check should be enabled + * + * @var bool + */ + protected $deep = false; + + /** + * Create a new E-mail address validator with optional options + * + * Optional options: + * + * 'mx' => If an MX check should be enabled, boolean + * 'deep' => If a deep MX check should be enabled, boolean + * + * @param array $options + * + * @throws Exception + */ + public function __construct(array $options = []) + { + if (array_key_exists('mx', $options)) { + $this->setEnableMxCheck($options['mx']); + } + + if (array_key_exists('deep', $options)) { + $this->setEnableDeepMxCheck($options['deep']); + } + } + + /** + * Set MX check + * + * To validate if the hostname is a DNS mail exchange (MX) record set it to true + * + * @param bool $mx if MX check should be enabled + * + * @return $this + */ + public function setEnableMxCheck(bool $mx = true): self + { + $this->mx = $mx; + + return $this; + } + + /** + * Set Deep MX check + * + * To validate if the hostname is a DNS mail exchange (MX) record, and it points to an A record (for IPv4) or + * an AAAA / A6 record (for IPv6) set it to true + * + * @param bool $deep if deep MX check should be enabled + * + * @return $this + * + * @throws Exception in case MX check has not been enabled + */ + public function setEnableDeepMxCheck(bool $deep = true): self + { + if (! $this->mx) { + throw new Exception("MX record check has to be enabled to enable deep MX record check"); + } + + $this->deep = $deep; + + return $this; + } + + /** + * Validate the local part (username / the part before '@') of the email address + * + * @param string $localPart + * @param string $email + * + * @return bool + */ + private function validateLocalPart(string $localPart, string $email): bool + { + // First try to match the local part on the common dot-atom format + $result = false; + + // Dot-atom characters are: 1*atext *("." 1*atext) + // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*", + // "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~" + $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d\x7e'; + if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $localPart)) { + $result = true; + } else { + // Try quoted string format (RFC 5321 Chapter 4.1.2) + + // Quoted-string characters are: DQUOTE *(qtext/quoted-pair) DQUOTE + $qtext = '\x20-\x21\x23-\x5b\x5d-\x7e'; // %d32-33 / %d35-91 / %d93-126 + $quotedPair = '\x20-\x7e'; // %d92 %d32-126 + if (preg_match('/^"([' . $qtext . ']|\x5c[' . $quotedPair . '])*"$/', $localPart)) { + $result = true; + } else { + $this->addMessage(sprintf( + $this->translate( + "'%s' can not be matched against dot-atom format or quoted-string format" + ), + $localPart + )); + $this->addMessage(sprintf( + $this->translate("Hence '%s' is not a valid local part for email address '%s'"), + $localPart, + $email + )); + } + } + + return $result; + } + + /** + * Validate the hostname part of the email address + * + * @param string $hostname + * @param string $email + * + * @return bool + */ + private function validateHostnamePart(string $hostname, string $email): bool + { + $hostValidator = new HostnameValidator(); + + if ($this->validateIp($hostname)) { + return true; + } + + if (preg_match('/^\[([^\]]*)\]$/i', $hostname, $matches)) { + $validHostname = $matches[1]; + if (! $this->validateIp($validHostname)) { + $this->addMessage(sprintf( + $this->translate("host name %s is a domain literal and is invalid"), + $hostname + )); + + return false; + } + + return true; + } + + if (! $hostValidator->isValid($hostname)) { + $this->addMessage(sprintf( + $this->translate('%s is not a valid domain name for email address %s.'), + $hostname, + $email + )); + + return false; + } elseif ($this->mx) { + // MX check on hostname + return $this->validateMXRecords($hostname, $email); + } + + return true; + } + + /** + * Check if the given IP address is valid + * + * @param string $value + * + * @return bool + */ + private function validateIp(string $value): bool + { + if (! filter_var($value, FILTER_VALIDATE_IP)) { + return false; + } + + return true; + } + + /** + * Returns true if and only if $value is a valid email address + * according to RFC2822 + * + * @param string $value + * + * @return bool + */ + public function isValid($value): bool + { + $this->clearMessages(); + + $matches = []; + $length = true; + + // Split email address up and disallow '..' + if ( + (strpos($value, '..') !== false) + || (! preg_match('/^(.+)@([^@]+)$/', $value, $matches)) + ) { + $this->addMessage(sprintf( + $this->translate("'%s' is not a valid email address in the basic format local-part@hostname"), + $value + )); + return false; + } + + $localPart = $matches[1]; + $hostname = $matches[2]; + + if ((strlen($localPart) > 64) || (strlen($hostname) > 255)) { + $length = false; + $this->addMessage(sprintf( + $this->translate("'%s' exceeds the allowed length"), + $value + )); + } + + $local = $this->validateLocalPart($localPart, $value); + + // If both parts valid, return true + if (($local && $this->validateHostnamePart($hostname, $value)) && $length) { + return true; + } + + return false; + } + + /** + * Perform deep MX record validation + * + * Check if the hostname is a valid DNS mail exchange (MX) record in case deep MX record check is enabled, + * also checks if the corresponding MX record points to an A record (for IPv4) or an AAAA / A6 record (for IPv6) + * + * @param string $hostname + * @param string $email + * + * @return bool + */ + private function validateMXRecords(string $hostname, string $email): bool + { + $mxHosts = []; + //decode IDN domain name + $decodedHostname = idn_to_ascii($hostname, 0, INTL_IDNA_VARIANT_UTS46); + + $result = getmxrr($decodedHostname, $mxHosts); + if (! $result) { + $this->addMessage(sprintf( + $this->translate("'%s' does not appear to have a valid MX record for the email address '%s'"), + $hostname, + $email + )); + } elseif ($this->deep) { + $validAddress = false; + $reserved = true; + foreach ($mxHosts as $decodedHostname) { + $res = $this->isReserved($decodedHostname); + if (! $res) { + $reserved = false; + } + + if ( + ! $res + && ( + checkdnsrr($decodedHostname, "A") + || checkdnsrr($decodedHostname, "AAAA") + || checkdnsrr($decodedHostname, "A6") + ) + ) { + $validAddress = true; + break; + } + } + + if (! $validAddress) { + $result = false; + if ($reserved) { + $this->addMessage(sprintf( + $this->translate( + "'%s' is not in a routable network segment." . + " The email address '%s' should not be resolved from public network" + ), + $hostname, + $email + )); + } else { + $this->addMessage(sprintf( + $this->translate("'%s' does not appear to have a valid MX record for the email address '%s'"), + $hostname, + $email + )); + } + } + } + + return $result; + } + + /** + * Validate whether the given host is reserved + * + * @param string $host host name or ip address + * + * @return bool + */ + private function isReserved(string $host): bool + { + if (! preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $host)) { + $host = gethostbyname($host); + } + + if (! filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE)) { + return true; + } + + return false; + } +} diff --git a/vendor/ipl/validator/src/FileValidator.php b/vendor/ipl/validator/src/FileValidator.php new file mode 100644 index 0000000..8c5b90e --- /dev/null +++ b/vendor/ipl/validator/src/FileValidator.php @@ -0,0 +1,248 @@ +setMinSize($options['minSize'] ?? 0) + ->setMaxSize($options['maxSize'] ?? null) + ->setMaxFileNameLength($options['maxFileNameLength'] ?? null) + ->setAllowedMimeTypes($options['mimeType'] ?? null); + } + + /** + * Get the minimum allowed file size + * + * @return int + */ + public function getMinSize(): int + { + return $this->minSize; + } + + /** + * Set the minimum allowed file size + * + * @param int $minSize + * + * @return $this + */ + public function setMinSize(int $minSize): self + { + if (($max = $this->getMaxSize()) !== null && $minSize > $max) { + throw new LogicException( + sprintf( + 'The minSize must be less than or equal to the maxSize, but minSize: %d and maxSize: %d given.', + $minSize, + $max + ) + ); + } + + $this->minSize = $minSize; + + return $this; + } + + /** + * Get the maximum allowed file size + * + * @return ?int + */ + public function getMaxSize(): ?int + { + return $this->maxSize; + } + + /** + * Set the maximum allowed file size + * + * @param ?int $maxSize + * + * @return $this + */ + public function setMaxSize(?int $maxSize): self + { + if ($maxSize !== null && ($min = $this->getMinSize()) !== null && $maxSize < $min) { + throw new LogicException( + sprintf( + 'The minSize must be less than or equal to the maxSize, but minSize: %d and maxSize: %d given.', + $min, + $maxSize + ) + ); + } + + $this->maxSize = $maxSize; + + return $this; + } + + /** + * Get the allowed file mime types + * + * @return ?string[] + */ + public function getAllowedMimeTypes(): ?array + { + return $this->allowedMimeTypes; + } + + /** + * Set the allowed file mime types + * + * @param ?string[] $allowedMimeTypes + * + * @return $this + */ + public function setAllowedMimeTypes(?array $allowedMimeTypes): self + { + $this->allowedMimeTypes = $allowedMimeTypes; + + return $this; + } + + /** + * Get maximum allowed file name length + * + * @return ?int + */ + public function getMaxFileNameLength(): ?int + { + return $this->maxFileNameLength; + } + + /** + * Set maximum allowed file name length + * + * @param ?int $maxFileNameLength + * + * @return $this + */ + public function setMaxFileNameLength(?int $maxFileNameLength): self + { + $this->maxFileNameLength = $maxFileNameLength; + + return $this; + } + + public function isValid($value) + { + // Multiple isValid() calls must not stack validation messages + $this->clearMessages(); + + if (is_array($value)) { + foreach ($value as $file) { + if (! $this->validateFile($file)) { + return false; + } + } + + return true; + } + + return $this->validateFile($value); + } + + + private function validateFile(UploadedFileInterface $file): bool + { + $isValid = true; + if ($this->getMaxSize() && $file->getSize() > $this->getMaxSize()) { + $this->addMessage(sprintf( + $this->translate('File %s is bigger than the allowed maximum size of %d'), + $file->getClientFileName(), + $this->getMaxSize() + )); + + $isValid = false; + } + + if ($this->getMinSize() && $file->getSize() < $this->getMinSize()) { + $this->addMessage(sprintf( + $this->translate('File %s is smaller than the minimum required size of %d'), + $file->getClientFileName(), + $this->getMinSize() + )); + + $isValid = false; + } + + if ($this->getMaxFileNameLength()) { + $strValidator = new StringLengthValidator(['max' => $this->getMaxFileNameLength()]); + + if (! $strValidator->isValid($file->getClientFilename())) { + $this->addMessage(sprintf( + $this->translate('File name is longer than the allowed length of %d characters.'), + $this->maxFileNameLength + )); + + $isValid = false; + } + } + + if (! empty($this->getAllowedMimeTypes())) { + $hasAllowedMimeType = false; + foreach ($this->getAllowedMimeTypes() as $type) { + $fileMimetype = $file->getClientMediaType(); + if (($pos = strpos($type, '/*')) !== false) { // image/* + $typePrefix = substr($type, 0, $pos); + if (Str::startsWith($fileMimetype, $typePrefix)) { + $hasAllowedMimeType = true; + break; + } + } elseif ($fileMimetype === $type) { // image/png + $hasAllowedMimeType = true; + break; + } + } + + if (! $hasAllowedMimeType) { + $this->addMessage(sprintf( + $this->translate('File %s is of type %s. Only %s allowed.'), + $file->getClientFileName(), + $file->getClientMediaType(), + implode(', ', $this->allowedMimeTypes) + )); + + $isValid = false; + } + } + + return $isValid; + } +} diff --git a/vendor/ipl/validator/src/GreaterThanValidator.php b/vendor/ipl/validator/src/GreaterThanValidator.php new file mode 100644 index 0000000..e5de3d0 --- /dev/null +++ b/vendor/ipl/validator/src/GreaterThanValidator.php @@ -0,0 +1,69 @@ +setMin($options['min'] ?? 0); + } + + /** + * Get the min option + * + * @return mixed + */ + public function getMin() + { + return $this->min; + } + + /** + * Set the min option + * + * @param mixed $min + * + * @return $this + */ + public function setMin($min): self + { + $this->min = $min; + + return $this; + } + + public function isValid($value) + { + // Multiple isValid() calls must not stack validation messages + $this->clearMessages(); + + if ($this->getMin() >= $value) { + $this->addMessage(sprintf( + $this->translate("'%s' is not greater than '%s'"), + $value, + $this->min + )); + + return false; + } + + return true; + } +} diff --git a/vendor/ipl/validator/src/HexColorValidator.php b/vendor/ipl/validator/src/HexColorValidator.php new file mode 100644 index 0000000..e2da39c --- /dev/null +++ b/vendor/ipl/validator/src/HexColorValidator.php @@ -0,0 +1,37 @@ +clearMessages(); + + if (! preg_match('/\A#[0-9a-f]{6}\z/i', $value)) { + $this->addMessage(sprintf( + $this->translate('Color string not in the expected format %s'), + '#rrggbb' + )); + + return false; + } + + return true; + } +} diff --git a/vendor/ipl/validator/src/HostnameValidator.php b/vendor/ipl/validator/src/HostnameValidator.php new file mode 100644 index 0000000..3bb9b66 --- /dev/null +++ b/vendor/ipl/validator/src/HostnameValidator.php @@ -0,0 +1,37 @@ +clearMessages(); + + $asciiHostname = idn_to_ascii($value, 0, INTL_IDNA_VARIANT_UTS46); + if (filter_var($asciiHostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) === false) { + $this->addMessage(sprintf( + $this->translate("%s is not a valid host name."), + $value ?? '' + )); + + return false; + } + + return true; + } +} diff --git a/vendor/ipl/validator/src/InArrayValidator.php b/vendor/ipl/validator/src/InArrayValidator.php new file mode 100644 index 0000000..f8c18ef --- /dev/null +++ b/vendor/ipl/validator/src/InArrayValidator.php @@ -0,0 +1,128 @@ +setHaystack($options['haystack']); + } + + $this->setStrict($options['strict'] ?? false); + } + + /** + * Get the haystack + * + * @return array + */ + public function getHaystack(): array + { + return $this->haystack ?? []; + } + + /** + * Set the haystack + * + * @param array $haystack + * + * @return $this + */ + public function setHaystack(array $haystack): self + { + $this->haystack = $haystack; + + return $this; + } + + /** + * Get whether the types of the needle in the haystack should also match + * + * @return bool + */ + public function isStrict(): bool + { + return $this->strict; + } + + /** + * Set whether the types of the needle in the haystack should also match + * + * @param bool $strict + * + * @return $this + */ + public function setStrict(bool $strict = true): self + { + $this->strict = $strict; + + return $this; + } + + public function isValid($value) + { + // Multiple isValid() calls must not stack validation messages + $this->clearMessages(); + + $notInArray = $this->findInvalid((array) $value); + + if (empty($notInArray)) { + return true; + } + + $this->addMessage(sprintf( + $this->translatePlural( + "%s was not found in the haystack", + "%s were not found in the haystack", + count($notInArray) + ), + implode(', ', $notInArray) + )); + + return false; + } + + /** + * Get the values from the specified array that are not present in the haystack + * + * @param array $values + * + * @return array Values not found in the haystack + */ + protected function findInvalid(array $values = []): array + { + $notInArray = []; + foreach ($values as $val) { + if (! in_array($val, $this->getHaystack(), $this->isStrict())) { + $notInArray[] = $val; + } + } + + return $notInArray; + } +} diff --git a/vendor/ipl/validator/src/LessThanValidator.php b/vendor/ipl/validator/src/LessThanValidator.php new file mode 100644 index 0000000..68e3daf --- /dev/null +++ b/vendor/ipl/validator/src/LessThanValidator.php @@ -0,0 +1,69 @@ +setMax($options['max'] ?? 0); + } + + /** + * Get the max option + * + * @return mixed + */ + public function getMax() + { + return $this->max; + } + + /** + * Set the max option + * + * @param mixed $max + * + * @return $this + */ + public function setMax($max): self + { + $this->max = $max; + + return $this; + } + + public function isValid($value) + { + // Multiple isValid() calls must not stack validation messages + $this->clearMessages(); + + if ($this->getMax() <= $value) { + $this->addMessage(sprintf( + $this->translate("'%s' is not less than '%s'"), + $value, + $this->getMax() + )); + + return false; + } + + return true; + } +} diff --git a/vendor/ipl/validator/src/PrivateKeyValidator.php b/vendor/ipl/validator/src/PrivateKeyValidator.php new file mode 100644 index 0000000..b629398 --- /dev/null +++ b/vendor/ipl/validator/src/PrivateKeyValidator.php @@ -0,0 +1,33 @@ +clearMessages(); + + if (preg_match('/\A\s*\w+:/', $value)) { + $this->addMessage($this->translate('URLs are not allowed')); + + return false; + } + + if (openssl_pkey_get_private($value) === false) { + $this->addMessage($this->translate('Not a valid PEM-encoded private key')); + + return false; + } + + return true; + } +} diff --git a/vendor/ipl/validator/src/StringLengthValidator.php b/vendor/ipl/validator/src/StringLengthValidator.php new file mode 100644 index 0000000..57df1eb --- /dev/null +++ b/vendor/ipl/validator/src/StringLengthValidator.php @@ -0,0 +1,179 @@ +setMin($options['min'] ?? 0) + ->setMax($options['max'] ?? null) + ->setEncoding($options['encoding'] ?? null); + } + + /** + * Get the minimum required string length + * + * @return mixed + */ + public function getMin() + { + return $this->min; + } + + /** + * Set the minimum required string length + * + * @param mixed $min + * + * @return $this + * + * @throws LogicException When the $min is greater than the $max value + */ + public function setMin($min): self + { + if ($this->getMax() !== null && $min > $this->getMax()) { + throw new LogicException( + sprintf( + 'The min must be less than or equal to the max length, but min: %d and max: %d given.', + $min, + $this->getMax() + ) + ); + } + + $this->min = $min; + + return $this; + } + + /** + * Get the maximum required string length + * + * @return mixed + */ + public function getMax() + { + return $this->max; + } + + /** + * Set the minimum required string length + * + * @param mixed $max + * + * @return $this + * + * @throws LogicException When the $min is greater than the $max value + */ + public function setMax($max): self + { + if ($max !== null && $this->getMin() > $max) { + throw new LogicException( + sprintf( + 'The min must be less than or equal to the max length, but min: %d and max: %d given.', + $this->getMin(), + $max + ) + ); + } + + $this->max = $max; + + return $this; + } + + /** + * Get the encoding type to use + * + * @return ?string + */ + public function getEncoding(): ?string + { + return $this->encoding; + } + + /** + * Set the encoding type to use + * + * @param ?string $encoding + * + * @return $this + */ + public function setEncoding(?string $encoding): self + { + if ($encoding !== null) { + $availableEncodings = array_map('strtolower', mb_list_encodings()); + if (! in_array(strtolower($encoding), $availableEncodings, true)) { + throw new InvalidArgumentException( + sprintf('Given encoding "%s" is not supported on this OS!', $encoding) + ); + } + } + + $this->encoding = $encoding; + + return $this; + } + + public function isValid($value) + { + // Multiple isValid() calls must not stack validation messages + $this->clearMessages(); + + if ($encoding = $this->getEncoding()) { // because encoding is only nullable in php >= 8.0 + $length = mb_strlen($value, $encoding); + } else { + $length = mb_strlen($value); + } + + if ($length < $this->getMin()) { + $this->addMessage(sprintf( + $this->translate('String should be %d characters long, %d given'), + $this->getMin(), + $length + )); + + return false; + } + + if ($this->getMax() && $this->getMax() < $length) { + $this->addMessage(sprintf( + $this->translate('String should be %d characters long, %d given'), + $this->getMax(), + $length + )); + + return false; + } + + return true; + } +} diff --git a/vendor/ipl/validator/src/ValidatorChain.php b/vendor/ipl/validator/src/ValidatorChain.php new file mode 100644 index 0000000..2860a12 --- /dev/null +++ b/vendor/ipl/validator/src/ValidatorChain.php @@ -0,0 +1,284 @@ +validators = new PriorityQueue(); + $this->validatorsThatBreakTheChain = new SplObjectStorage(); + + $this->addDefaultPluginLoader('validator', __NAMESPACE__, 'Validator'); + } + + /** + * Get the validators that break the chain + * + * @return SplObjectStorage + */ + public function getValidatorsThatBreakTheChain() + { + return $this->validatorsThatBreakTheChain; + } + + /** + * Add a validator to the chain + * + * If $breakChainOnFailure is true and the validator fails, subsequent validators won't be executed. + * + * @param Validator $validator + * @param bool $breakChainOnFailure + * @param int $priority Priority at which to add validator + * + * @return $this + * + */ + public function add(Validator $validator, $breakChainOnFailure = false, $priority = self::DEFAULT_PRIORITY) + { + $this->validators->insert($validator, $priority); + + if ($breakChainOnFailure) { + $this->validatorsThatBreakTheChain->attach($validator); + } + + return $this; + } + + /** + * Add the validators from the given validator specification to the chain + * + * @param iterable $validators + * + * @return $this + * + * @throws InvalidArgumentException If $validators is not iterable or if the validator specification is invalid + */ + public function addValidators($validators) + { + if ($validators instanceof static) { + return $this->merge($validators); + } + + if (! is_iterable($validators)) { + throw new InvalidArgumentException(sprintf( + '%s expects parameter one to be iterable, got %s instead', + __METHOD__, + get_php_type($validators) + )); + } + + foreach ($validators as $name => $validator) { + $breakChainOnFailure = false; + + if (! $validator instanceof Validator) { + if (is_int($name)) { + if (! is_array($validator)) { + $name = $validator; + $validator = null; + } else { + if (! isset($validator['name'])) { + throw new InvalidArgumentException( + 'Invalid validator array specification: Key "name" is missing' + ); + } + + $name = $validator['name']; + unset($validator['name']); + } + } + + if (is_array($validator)) { + if (isset($validator['options'])) { + $options = $validator['options']; + + unset($validator['options']); + + $validator = array_merge($validator, $options); + } + + if (isset($validator['break_chain_on_failure'])) { + $breakChainOnFailure = $validator['break_chain_on_failure']; + + unset($validator['break_chain_on_failure']); + } + } + + $validator = $this->createValidator($name, $validator); + } + + $this->add($validator, $breakChainOnFailure); + } + + return $this; + } + + /** + * Add a validator loader + * + * @param string $namespace Namespace of the validators + * @param string $postfix Validator name postfix, if any + * + * @return $this + */ + public function addValidatorLoader($namespace, $postfix = null) + { + $this->addPluginLoader('validator', $namespace, $postfix); + + return $this; + } + + /** + * Remove all validators from the chain + * + * @return $this + */ + public function clearValidators() + { + $this->validators = new PriorityQueue(); + $this->validatorsThatBreakTheChain = new SplObjectStorage(); + + return $this; + } + + /** + * Create a validator from the given name and options + * + * @param string $name + * @param mixed $options + * + * @return Validator + * + * @throws InvalidArgumentException If the validator to load is unknown + * @throws UnexpectedValueException If a validator loader did not return an instance of {@link Validator} + */ + public function createValidator($name, $options = null) + { + $class = $this->loadPlugin('validator', $name); + + if (! $class) { + throw new InvalidArgumentException(sprintf( + "Can't load validator '%s'. Validator unknown", + $name + )); + } + + if (empty($options)) { + $validator = new $class(); + } else { + $validator = new $class($options); + } + + if (! $validator instanceof Validator) { + throw new UnexpectedValueException(sprintf( + "%s expects loader to return an instance of %s for validator '%s', got %s instead", + __METHOD__, + Validator::class, + $name, + get_php_type($validator) + )); + } + + return $validator; + } + + /** + * Merge all validators from the given chain into this one + * + * @param ValidatorChain $validatorChain + * + * @return $this + */ + public function merge(ValidatorChain $validatorChain) + { + $validatorsThatBreakTheChain = $validatorChain->getValidatorsThatBreakTheChain(); + + foreach ($validatorChain->validators->yieldAll() as $priority => $validator) { + $this->add($validator, $validatorsThatBreakTheChain->contains($validator), $priority); + } + + return $this; + } + + public function __clone() + { + $this->validators = clone $this->validators; + } + + /** + * Export the chain as array + * + * @return array + */ + public function toArray() + { + return array_values(iterator_to_array($this)); + } + + public function count(): int + { + return count($this->validators); + } + + /** + * Get an iterator for traversing the validators + * + * @return Validator[]|PriorityQueue + */ + public function getIterator(): Traversable + { + // Clone validators because the PriorityQueue acts as a heap and thus items are removed upon iteration + return clone $this->validators; + } + + public function isValid($value) + { + $this->clearMessages(); + + $valid = true; + + foreach ($this as $validator) { + if ($validator->isValid($value)) { + continue; + } + + $valid = false; + + $this->addMessages($validator->getMessages()); + + if ($this->validatorsThatBreakTheChain->contains($validator)) { + break; + } + } + + return $valid; + } +} diff --git a/vendor/ipl/validator/src/X509CertValidator.php b/vendor/ipl/validator/src/X509CertValidator.php new file mode 100644 index 0000000..7dfc4f7 --- /dev/null +++ b/vendor/ipl/validator/src/X509CertValidator.php @@ -0,0 +1,33 @@ +clearMessages(); + + if (preg_match('/\A\s*\w+:/', $value)) { + $this->addMessage($this->translate('URLs are not allowed')); + + return false; + } + + if (openssl_x509_parse($value) === false) { + $this->addMessage($this->translate('Not a valid PEM-encoded X.509 certificate')); + + return false; + } + + return true; + } +} -- cgit v1.2.3