• Модуль: main
  • Путь к файлу: ~/bitrix/modules/main/lib/security/mfa/totpalgorithm.php
  • Класс: BitrixMainSecurityMfaTotpAlgorithm
  • Вызов: TotpAlgorithm::verify
public function verify($input, $params = null, $time = null)
{
	$input = (string)$input;

	if ($params === null)
	{
		$params = '0:0';
	}

	if (!preg_match('#^d+$#D', $input))
	{
		throw new ArgumentOutOfRangeException('input', 'string with numbers');
	}

	[$userOffset, $lastTimeCode] = explode(':', $params);
	$userOffset = (int)$userOffset;
	$lastTimeCode = (int)$lastTimeCode;

	if ($time === null)
	{
		$timeCode = $this->timecode(time());
	}
	else
	{
		$timeCode = $this->timecode((int)$time);
	}

	$checkOffsets = [];
	// First of all we must check input for provided offset
	$checkOffsets[] = $userOffset;
	if ($userOffset)
	{
		// If we failed on previous step and have user offset - try current time, may be user syncing time on device
		$checkOffsets[] = 0;
	}

	if ($this->window)
	{
		// Otherwise, try deal with clock drifting
		$checkOffsets = array_merge(
			$checkOffsets,
			range($userOffset - $this->window, $userOffset + $this->window)
		);
	}

	$isSuccess = false;
	$resultOffset = 0;
	$resultTimeCode = 0;

	foreach ($checkOffsets as $offset)
	{
		$code = $timeCode + $offset;
		// Disallow authorization in the past. Must prevent replay attacks.
		if ($lastTimeCode && $code <= $lastTimeCode)
		{
			continue;
		}

		if ($this->isStringsEqual($input, $this->generateOTP($code)))
		{
			$isSuccess = true;
			$resultOffset = $offset;
			$resultTimeCode = $code;
			break;
		}
	}

	if ($isSuccess === true)
	{
		return [true, sprintf('%d:%d', $resultOffset, $resultTimeCode)];
	}

	return [false, null];
}