Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?phpdeclare(strict_types=1);/** The MIT License (MIT)** Copyright (c) 2014-2018 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;final class TOTP extends OTP implements TOTPInterface{/*** TOTP constructor.** @param string|null $secret* @param int $period* @param string $digest* @param int $digits* @param int $epoch*/protected function __construct($secret, int $period, string $digest, int $digits, int $epoch = 0){parent::__construct($secret, $digest, $digits);$this->setPeriod($period);$this->setEpoch($epoch);}/*** TOTP constructor.** @param string|null $secret* @param int $period* @param string $digest* @param int $digits* @param int $epoch** @return self*/public static function create($secret = null, int $period = 30, string $digest = 'sha1', int $digits = 6, int $epoch = 0): self{return new self($secret, $period, $digest, $digits, $epoch);}/*** @param int $period*/protected function setPeriod(int $period){$this->setParameter('period', $period);}/*** {@inheritdoc}*/public function getPeriod(): int{return $this->getParameter('period');}/*** @param int $epoch*/private function setEpoch(int $epoch){$this->setParameter('epoch', $epoch);}/*** {@inheritdoc}*/public function getEpoch(): int{return $this->getParameter('epoch');}/*** {@inheritdoc}*/public function at(int $timestamp): string{return $this->generateOTP($this->timecode($timestamp));}/*** {@inheritdoc}*/public function now(): string{return $this->at(time());}/*** If no timestamp is provided, the OTP is verified at the actual timestamp* {@inheritdoc}*/public function verify(string $otp, $timestamp = null, $window = null): bool{$timestamp = $this->getTimestamp($timestamp);if (null === $window) {return $this->compareOTP($this->at($timestamp), $otp);}return $this->verifyOtpWithWindow($otp, $timestamp, $window);}/*** @param string $otp* @param int $timestamp* @param int $window** @return bool*/private function verifyOtpWithWindow(string $otp, int $timestamp, int $window): bool{$window = abs($window);for ($i = 0; $i <= $window; $i++) {$next = (int) $i * $this->getPeriod() + $timestamp;$previous = (int) -$i * $this->getPeriod() + $timestamp;$valid = $this->compareOTP($this->at($next), $otp) ||$this->compareOTP($this->at($previous), $otp);if ($valid) {return true;}}return false;}/*** @param int|null $timestamp** @return int*/private function getTimestamp($timestamp): int{$timestamp = $timestamp ?? time();Assertion::greaterOrEqualThan($timestamp, 0, 'Timestamp must be at least 0.');return (int) $timestamp;}/*** {@inheritdoc}*/public function getProvisioningUri(): string{$params = [];if (30 !== $this->getPeriod()) {$params['period'] = $this->getPeriod();}if (0 !== $this->getEpoch()) {$params['epoch'] = $this->getEpoch();}return $this->generateURI('totp', $params);}/*** @param int $timestamp** @return int*/private function timecode(int $timestamp): int{return (int) floor(($timestamp - $this->getEpoch()) / $this->getPeriod());}/*** {@inheritdoc}*/protected function getParameterMap(): array{$v = array_merge(parent::getParameterMap(),['period' => function ($value) {Assertion::greaterThan((int) $value, 0, 'Period must be at least 1.');return (int) $value;},'epoch' => function ($value) {Assertion::greaterOrEqualThan((int) $value, 0, 'Epoch must be greater than or equal to 0.');return (int) $value;},]);return $v;}/*** {@inheritdoc}*/protected function filterOptions(array &$options){parent::filterOptions($options);if (isset($options['epoch']) && 0 === $options['epoch']) {unset($options['epoch']);}ksort($options);}}