aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/spomky-labs/otphp/src/Factory.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/spomky-labs/otphp/src/Factory.php')
-rw-r--r--vendor/spomky-labs/otphp/src/Factory.php85
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];
+ }
+}