/**
  * Validate a sequence of multi-factor authentication parameters.
  *
  * @param MfaConfigurationInterface      $configuration      The configuration to use for validation.
  * @param MfaSharedParametersInterface   $shared             The shared parameters to use for validation.
  * @param array<MfaCredentialsInterface> $credentialSequence The sequence of credentials to validate.
  *
  * @return Result\MfaValidationResultInterface The validation result.
  */
 public function validateSequence(MfaConfigurationInterface $configuration, MfaSharedParametersInterface $shared, array $credentialSequence)
 {
     if (count($credentialSequence) < 1) {
         return new CounterBasedOtpValidationResult(CounterBasedOtpValidationResult::EMPTY_CREDENTIAL_SEQUENCE);
     }
     $first = true;
     $counter = $shared->counter();
     foreach ($credentialSequence as $credentials) {
         if ($first) {
             $window = $configuration->window();
         } else {
             $window = 0;
         }
         $currentConfiguration = clone $configuration;
         $currentConfiguration->setWindow($window);
         $currentShared = clone $shared;
         $currentShared->setCounter($counter);
         $result = $this->validate($currentConfiguration, $currentShared, $credentials);
         if (!$result->isSuccessful()) {
             break;
         }
         $counter = $result->counter();
         $first = false;
     }
     return $result;
 }
 /**
  * Validate a set of multi-factor authentication parameters.
  *
  * @param MfaConfigurationInterface    $configuration The configuration to use for validation.
  * @param MfaSharedParametersInterface $shared        The shared parameters to use for validation.
  * @param MfaCredentialsInterface      $credentials   The credentials to validate.
  *
  * @return Result\MfaValidationResultInterface The validation result.
  */
 public function validate(MfaConfigurationInterface $configuration, MfaSharedParametersInterface $shared, MfaCredentialsInterface $credentials)
 {
     if (strlen($credentials->password()) !== $configuration->digits()) {
         return new TimeBasedOtpValidationResult(TimeBasedOtpValidationResult::CREDENTIAL_LENGTH_MISMATCH);
     }
     for ($i = -$configuration->pastWindows(); $i <= $configuration->futureWindows(); ++$i) {
         $currentShared = clone $shared;
         $currentShared->setTime($shared->time() + $i * $configuration->window());
         $value = $this->generator()->generate($configuration, $currentShared);
         if ($credentials->password() === $value->string($configuration->digits())) {
             return new TimeBasedOtpValidationResult(TimeBasedOtpValidationResult::VALID, $i);
         }
     }
     return new TimeBasedOtpValidationResult(TimeBasedOtpValidationResult::INVALID_CREDENTIALS);
 }