diff options
Diffstat (limited to 'vendor/spomky-labs/otphp/src/HOTP.php')
| -rw-r--r-- | vendor/spomky-labs/otphp/src/HOTP.php | 128 |
1 files changed, 81 insertions, 47 deletions
diff --git a/vendor/spomky-labs/otphp/src/HOTP.php b/vendor/spomky-labs/otphp/src/HOTP.php index a2f4a2395..835de35f3 100644 --- a/vendor/spomky-labs/otphp/src/HOTP.php +++ b/vendor/spomky-labs/otphp/src/HOTP.php @@ -2,60 +2,78 @@ declare(strict_types=1); -/* - * The MIT License (MIT) - * - * Copyright (c) 2014-2019 Spomky-Labs - * - * This software may be modified and distributed under the terms - * of the MIT license. See the LICENSE file for details. - */ - namespace OTPHP; -use Assert\Assertion; +use InvalidArgumentException; +use function is_int; +/** + * @see \OTPHP\Test\HOTPTest + */ final class HOTP extends OTP implements HOTPInterface { - protected function __construct(?string $secret, int $counter, string $digest, int $digits) - { - parent::__construct($secret, $digest, $digits); - $this->setCounter($counter); + private const DEFAULT_WINDOW = 0; + + public static function create( + null|string $secret = null, + int $counter = self::DEFAULT_COUNTER, + string $digest = self::DEFAULT_DIGEST, + int $digits = self::DEFAULT_DIGITS + ): self { + $htop = $secret !== null + ? self::createFromSecret($secret) + : self::generate() + ; + $htop->setCounter($counter); + $htop->setDigest($digest); + $htop->setDigits($digits); + + return $htop; } - public static function create(?string $secret = null, int $counter = 0, string $digest = 'sha1', int $digits = 6): HOTPInterface + public static function createFromSecret(string $secret): self { - return new self($secret, $counter, $digest, $digits); + $htop = new self($secret); + $htop->setCounter(self::DEFAULT_COUNTER); + $htop->setDigest(self::DEFAULT_DIGEST); + $htop->setDigits(self::DEFAULT_DIGITS); + + return $htop; } - protected function setCounter(int $counter): void + public static function generate(): self { - $this->setParameter('counter', $counter); + return self::createFromSecret(self::generateSecret()); } + /** + * @return 0|positive-int + */ public function getCounter(): int { - return $this->getParameter('counter'); - } + $value = $this->getParameter('counter'); + (is_int($value) && $value >= 0) || throw new InvalidArgumentException('Invalid "counter" parameter.'); - private function updateCounter(int $counter): void - { - $this->setCounter($counter); + return $value; } public function getProvisioningUri(): string { - return $this->generateURI('hotp', ['counter' => $this->getCounter()]); + return $this->generateURI('hotp', [ + 'counter' => $this->getCounter(), + ]); } /** * If the counter is not provided, the OTP is verified at the actual counter. + * + * @param null|0|positive-int $counter */ - public function verify(string $otp, ?int $counter = null, ?int $window = null): bool + public function verify(string $otp, null|int $counter = null, null|int $window = null): bool { - Assertion::greaterOrEqualThan($counter, 0, 'The counter must be at least 0.'); + $counter >= 0 || throw new InvalidArgumentException('The counter must be at least 0.'); - if (null === $counter) { + if ($counter === null) { $counter = $this->getCounter(); } elseif ($counter < $this->getCounter()) { return false; @@ -64,12 +82,45 @@ final class HOTP extends OTP implements HOTPInterface return $this->verifyOtpWithWindow($otp, $counter, $window); } - private function getWindow(?int $window): int + public function setCounter(int $counter): void + { + $this->setParameter('counter', $counter); + } + + /** + * @return array<non-empty-string, callable> + */ + protected function getParameterMap(): array + { + return [...parent::getParameterMap(), ...[ + 'counter' => static function (mixed $value): int { + $value = (int) $value; + $value >= 0 || throw new InvalidArgumentException('Counter must be at least 0.'); + + return $value; + }, + ]]; + } + + private function updateCounter(int $counter): void + { + $this->setCounter($counter); + } + + /** + * @param null|0|positive-int $window + */ + private function getWindow(null|int $window): int { - return abs($window ?? 0); + return abs($window ?? self::DEFAULT_WINDOW); } - private function verifyOtpWithWindow(string $otp, int $counter, ?int $window): bool + /** + * @param non-empty-string $otp + * @param 0|positive-int $counter + * @param null|0|positive-int $window + */ + private function verifyOtpWithWindow(string $otp, int $counter, null|int $window): bool { $window = $this->getWindow($window); @@ -83,21 +134,4 @@ final class HOTP extends OTP implements HOTPInterface return false; } - - /** - * @return array<string, mixed> - */ - protected function getParameterMap(): array - { - $v = array_merge( - parent::getParameterMap(), - ['counter' => function ($value): int { - Assertion::greaterOrEqualThan((int) $value, 0, 'Counter must be at least 0.'); - - return (int) $value; - }] - ); - - return $v; - } } |