/** * @param string $number */ public function __construct($number) { if (!is_string($number)) { throw InvalidArgumentException::invalidType('string', 'number', $number); } if (!preg_match('~^\\d+$~', $number)) { throw new InvalidPhoneNumberFormatException($number); } $this->number = $number; }
/** * @param string $type */ public function __construct($type) { if (!is_string($type)) { throw InvalidArgumentException::invalidType('string', 'type', $type); } if (!isset(self::$loaLevelTypeMap[$type])) { throw new DomainException(sprintf("Invalid second factor type, got '%s', expected one of '%s'", $type, join(',', array_keys(self::$loaLevelTypeMap)))); } $this->type = $type; }
/** * @param string[] $locales * @param RequestStack $requestStack */ public function __construct(array $locales, RequestStack $requestStack) { foreach ($locales as $index => $locale) { if (!is_string($locale)) { throw InvalidArgumentException::invalidType('string', sprintf('locales[%s]', $index), $locale); } } $this->locales = $locales; $this->requestStack = $requestStack; }
/** * @param string $string a well formatted "+{CountryCode} (0) {PhoneNumber}" international phone number * @return InternationalPhoneNumber */ public static function fromStringFormat($string) { if (!is_string($string)) { throw InvalidArgumentException::invalidType('string', 'string', $string); } if (!preg_match('~^\\+([^\\(]+)\\(0\\)\\s{1}([\\d]+)$~', $string, $matches)) { throw new InvalidPhoneNumberFormatException('In order to create the phone number from string, it must have the format "+31 (0) 614696076", formal: ' . '"+{CountryCode} (0) {PhoneNumber}"'); } $countryCode = str_replace(' ', '', $matches[1]); $phoneNumber = $matches[2]; return new self(new CountryCode($countryCode), new PhoneNumber($phoneNumber)); }
/** * @param int $level * @param string $identifier */ public function __construct($level, $identifier) { $possibleLevels = [self::LOA_1, self::LOA_2, self::LOA_3]; if (!in_array($level, $possibleLevels, true)) { throw new DomainException(sprintf('Unknown loa level "%s", known levels: "%s"', is_object($level) ? get_class($level) : $level, implode('", "', $possibleLevels))); } if (!is_string($identifier)) { throw InvalidArgumentException::invalidType('string', 'identifier', $identifier); } $this->level = $level; $this->identifier = $identifier; }
/** * @param SmsService $smsService * @param SmsVerificationStateHandler $smsVerificationStateHandler * @param string $originator */ public function __construct(SmsService $smsService, SmsVerificationStateHandler $smsVerificationStateHandler, $originator) { if (!is_string($originator)) { throw InvalidArgumentException::invalidType('string', 'originator', $originator); } if (!preg_match('~^[a-z0-9]{1,11}$~i', $originator)) { throw new InvalidArgumentException('Invalid SMS originator given: may only contain alphanumerical characters.'); } $this->smsService = $smsService; $this->smsVerificationStateHandler = $smsVerificationStateHandler; $this->originator = $originator; }
/** * @param string $countyCode */ public function __construct($countyCode) { if (!is_string($countyCode)) { throw InvalidArgumentException::invalidType('string', 'countryCodeDefinition', $countyCode); } if (!preg_match('~^\\d+$~', $countyCode)) { throw new InvalidCountryCodeFormatException($countyCode); } if (!CountryCodeListing::isValidCountryCode($countyCode)) { throw UnknownCountryCodeException::unknownCountryCode($countyCode); } $this->countryCode = $countyCode; }
public function verify($userOtp) { if (!is_string($userOtp)) { throw InvalidArgumentException::invalidType('string', 'userOtp', $userOtp); } if (strtoupper($userOtp) !== strtoupper($this->otp)) { return OtpVerification::noMatch(); } $expiryTime = clone $this->issuedAt; $expiryTime->add($this->expiryInterval); if ($expiryTime <= DateTime::now()) { return OtpVerification::matchExpired(); } return OtpVerification::foundMatch($this->phoneNumber); }
public function __construct($value) { if (!is_string($value)) { throw InvalidArgumentException::invalidType('string', 'value', $value); } // Numeric IDs must be left-padded with zeroes until eight characters. Longer IDs may not be padded. if (!preg_match('~^\\d+$~', $value)) { throw new InvalidArgumentException('Given Yubikey public ID is not a string of digits'); } if ($value !== sprintf('%08s', ltrim($value, '0'))) { throw new InvalidArgumentException('Given Yubikey public ID is longer than 8 digits, yet left-padded with zeroes'); } // Yubikey public IDs, in their (mod)hex format, may be up to sixteen characters in length. Thus, this is their // maximum value. if (gmp_cmp(gmp_init($value, 10), gmp_init('ffffffffffffffff', 16)) > 0) { throw new InvalidArgumentException('Given Yubikey public ID is larger than 0xffffffffffffffff'); } $this->value = $value; }
/** * Securely generate a 8-character OTP containing only characters from the OtpGenerator::CHARACTER_SET constant. * Based on https://gist.github.com/pmeulen/3dff8bab3227ed340dd1 * * @param int $length The length of the OTP to generate * @return string * @throws OtpGenerationRuntimeException */ public static function generate($length) { if (!is_int($length)) { throw InvalidArgumentException::invalidType('int', 'length', $length); } if ($length <= 0) { throw new InvalidArgumentException('Expected positive integer $length'); } $bitsPerValue = self::BITS_PER_CHARACTER; $randomBytesRequired = (int) ceil($length * $bitsPerValue / 8); $cryptoStrong = false; $randomBytes = openssl_random_pseudo_bytes($randomBytesRequired, $cryptoStrong); // Generate random bytes if ($cryptoStrong === false) { throw new OtpGenerationRuntimeException('openssl_random_pseudo_bytes() is not cryptographically strong'); } if ($randomBytes === false) { throw new OtpGenerationRuntimeException('openssl_random_pseudo_bytes() failed'); } // Transform each byte $random_bytes into $random_bits where each byte // is converted to its 8 character ASCII binary representation. // This allows us to work with the individual bits using the php string functions // Not very efficient, but easy to understand. $randomBits = ''; for ($i = 0; $i < $randomBytesRequired; $i++) { $randomBits .= str_pad(decbin(ord($randomBytes[$i])), 8, '0', STR_PAD_LEFT); } // Get 'bits' form $random_bits string in blocks of 5 bits, convert bits to value [0..32> and use // this as offset in self::CHARACTER_SET to pick the character $password = ''; for ($i = 0; $i < $length; $i++) { $randomValueBin = substr($randomBits, $i * $bitsPerValue, $bitsPerValue); $password .= substr(self::CHARACTER_SET, bindec($randomValueBin), 1); } return $password; }
public function __construct($invalidCode) { parent::__construct(sprintf('A CountryCode may only contain digits, "%s" given', $invalidCode)); }
public function __construct($invalidFormat) { parent::__construct(sprintf('A PhoneNumber may only contain digits, "%s" given', $invalidFormat)); }
/** * @param string $userOtp * @return OtpVerification */ public function verify($userOtp) { if ($this->verificationAttemptsMade >= self::MAXIMUM_VERIFICATION_ATTEMPTS) { return OtpVerification::tooManyAttempts(); } $this->verificationAttemptsMade++; if (!is_string($userOtp)) { throw InvalidArgumentException::invalidType('string', 'userOtp', $userOtp); } foreach ($this->otps as $otp) { $verification = $otp->verify($userOtp); if ($verification->didOtpMatch()) { return $verification; } } return OtpVerification::noMatch(); }