diff options
Diffstat (limited to 'vendor/spomky-labs/otphp/src/Factory.php')
-rw-r--r-- | vendor/spomky-labs/otphp/src/Factory.php | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/vendor/spomky-labs/otphp/src/Factory.php b/vendor/spomky-labs/otphp/src/Factory.php new file mode 100644 index 000000000..d5c60cc34 --- /dev/null +++ b/vendor/spomky-labs/otphp/src/Factory.php @@ -0,0 +1,85 @@ +<?php + +declare(strict_types=1); + +namespace OTPHP; + +use function count; +use InvalidArgumentException; +use Throwable; + +/** + * This class is used to load OTP object from a provisioning Uri. + * + * @see \OTPHP\Test\FactoryTest + */ +final class Factory implements FactoryInterface +{ + public static function loadFromProvisioningUri(string $uri): OTPInterface + { + try { + $parsed_url = Url::fromString($uri); + $parsed_url->getScheme() === 'otpauth' || throw new InvalidArgumentException('Invalid scheme.'); + } catch (Throwable $throwable) { + throw new InvalidArgumentException('Not a valid OTP provisioning URI', $throwable->getCode(), $throwable); + } + + $otp = self::createOTP($parsed_url); + + self::populateOTP($otp, $parsed_url); + + return $otp; + } + + private static function populateParameters(OTPInterface $otp, Url $data): void + { + foreach ($data->getQuery() as $key => $value) { + $otp->setParameter($key, $value); + } + } + + private static function populateOTP(OTPInterface $otp, Url $data): void + { + self::populateParameters($otp, $data); + $result = explode(':', rawurldecode(mb_substr($data->getPath(), 1))); + + if (count($result) < 2) { + $otp->setIssuerIncludedAsParameter(false); + + return; + } + + if ($otp->getIssuer() !== null) { + $result[0] === $otp->getIssuer() || throw new InvalidArgumentException( + 'Invalid OTP: invalid issuer in parameter' + ); + $otp->setIssuerIncludedAsParameter(true); + } + $otp->setIssuer($result[0]); + } + + private static function createOTP(Url $parsed_url): OTPInterface + { + switch ($parsed_url->getHost()) { + case 'totp': + $totp = TOTP::createFromSecret($parsed_url->getSecret()); + $totp->setLabel(self::getLabel($parsed_url->getPath())); + + return $totp; + case 'hotp': + $hotp = HOTP::createFromSecret($parsed_url->getSecret()); + $hotp->setLabel(self::getLabel($parsed_url->getPath())); + + return $hotp; + default: + throw new InvalidArgumentException(sprintf('Unsupported "%s" OTP type', $parsed_url->getHost())); + } + } + + private static function getLabel(string $data): string + { + $result = explode(':', rawurldecode(mb_substr($data, 1))); + + return count($result) === 2 ? $result[1] : $result[0]; + } +} |