diff options
Diffstat (limited to 'vendor/spomky-labs/otphp/src/ParameterTrait.php')
-rw-r--r-- | vendor/spomky-labs/otphp/src/ParameterTrait.php | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/vendor/spomky-labs/otphp/src/ParameterTrait.php b/vendor/spomky-labs/otphp/src/ParameterTrait.php new file mode 100644 index 000000000..b05092351 --- /dev/null +++ b/vendor/spomky-labs/otphp/src/ParameterTrait.php @@ -0,0 +1,188 @@ +<?php + +declare(strict_types=1); + +namespace OTPHP; + +use function array_key_exists; +use function in_array; +use InvalidArgumentException; +use function is_int; +use function is_string; + +trait ParameterTrait +{ + /** + * @var array<string, mixed> + */ + private array $parameters = []; + + private null|string $issuer = null; + + private null|string $label = null; + + private bool $issuer_included_as_parameter = true; + + /** + * @return array<string, mixed> + */ + public function getParameters(): array + { + $parameters = $this->parameters; + + if ($this->getIssuer() !== null && $this->isIssuerIncludedAsParameter() === true) { + $parameters['issuer'] = $this->getIssuer(); + } + + return $parameters; + } + + public function getSecret(): string + { + $value = $this->getParameter('secret'); + is_string($value) || throw new InvalidArgumentException('Invalid "secret" parameter.'); + + return $value; + } + + public function getLabel(): null|string + { + return $this->label; + } + + public function setLabel(string $label): void + { + $this->setParameter('label', $label); + } + + public function getIssuer(): null|string + { + return $this->issuer; + } + + public function setIssuer(string $issuer): void + { + $this->setParameter('issuer', $issuer); + } + + public function isIssuerIncludedAsParameter(): bool + { + return $this->issuer_included_as_parameter; + } + + public function setIssuerIncludedAsParameter(bool $issuer_included_as_parameter): void + { + $this->issuer_included_as_parameter = $issuer_included_as_parameter; + } + + public function getDigits(): int + { + $value = $this->getParameter('digits'); + is_int($value) || throw new InvalidArgumentException('Invalid "digits" parameter.'); + + return $value; + } + + public function getDigest(): string + { + $value = $this->getParameter('algorithm'); + is_string($value) || throw new InvalidArgumentException('Invalid "algorithm" parameter.'); + + return $value; + } + + public function hasParameter(string $parameter): bool + { + return array_key_exists($parameter, $this->parameters); + } + + public function getParameter(string $parameter): mixed + { + if ($this->hasParameter($parameter)) { + return $this->getParameters()[$parameter]; + } + + throw new InvalidArgumentException(sprintf('Parameter "%s" does not exist', $parameter)); + } + + public function setParameter(string $parameter, mixed $value): void + { + $map = $this->getParameterMap(); + + if (array_key_exists($parameter, $map) === true) { + $callback = $map[$parameter]; + $value = $callback($value); + } + + if (property_exists($this, $parameter)) { + $this->{$parameter} = $value; + } else { + $this->parameters[$parameter] = $value; + } + } + + public function setSecret(string $secret): void + { + $this->setParameter('secret', $secret); + } + + public function setDigits(int $digits): void + { + $this->setParameter('digits', $digits); + } + + public function setDigest(string $digest): void + { + $this->setParameter('algorithm', $digest); + } + + /** + * @return array<string, callable> + */ + protected function getParameterMap(): array + { + return [ + 'label' => function ($value) { + $this->hasColon($value) === false || throw new InvalidArgumentException( + 'Label must not contain a colon.' + ); + + return $value; + }, + 'secret' => static fn ($value): string => mb_strtoupper(trim((string) $value, '=')), + 'algorithm' => static function ($value): string { + $value = mb_strtolower($value); + in_array($value, hash_algos(), true) || throw new InvalidArgumentException(sprintf( + 'The "%s" digest is not supported.', + $value + )); + + return $value; + }, + 'digits' => static function ($value): int { + $value > 0 || throw new InvalidArgumentException('Digits must be at least 1.'); + + return (int) $value; + }, + 'issuer' => function ($value) { + $this->hasColon($value) === false || throw new InvalidArgumentException( + 'Issuer must not contain a colon.' + ); + + return $value; + }, + ]; + } + + private function hasColon(string $value): bool + { + $colons = [':', '%3A', '%3a']; + foreach ($colons as $colon) { + if (str_contains($value, $colon)) { + return true; + } + } + + return false; + } +} |