You are here

function recaptcha_v3_validate in reCAPTCHA v3 8

CAPTCHA Callback; Validates the reCAPTCHA v3 code.

2 string references to 'recaptcha_v3_validate'
recaptcha_v3_captcha in ./recaptcha_v3.module
Implements hook_captcha().
recaptcha_v3_post_captcha_element_process in ./recaptcha_v3.module
Replace #captcha_validate by reCAPTCHA v3 validation function.

File

./recaptcha_v3.module, line 198
Contains recaptcha_v3.module.

Code

function recaptcha_v3_validate($solution, $captcha_response, $element, FormStateInterface $form_state) {

  // Using user input instead of $captcha_response variable, because
  // recaptcha using '#value' form api key for the 'captcha_response' form
  // element:
  // $captcha['form']['captcha_response'] = [
  //  '#type' => 'hidden',
  //  '#value' => 'Google no captcha', // Problem is here
  // ];
  // So if using recaptcha as fallback challenge, $captcha_response is always
  // have 'Google no captcha' value.
  $user_input = $form_state
    ->getUserInput();
  if (!empty($user_input['captcha_response'])) {
    $captcha_response = $user_input['captcha_response'];
  }
  $captcha_type_challenge = $form_state
    ->getTemporaryValue('recaptcha_v3_action_name');

  /** @var ReCaptchaV3ActionInterface $recaptcha_v3 */
  $recaptcha_v3 = ReCaptchaV3Action::load($captcha_type_challenge) ?? ReCaptchaV3Action::create([
    'id' => '',
    'label' => '',
    'threshold' => 1,
    'challenge' => 'default',
  ]);

  // Verify submitted reCAPTCHA v3 token.
  $verification_response = _recaptcha_v3_verify_captcha_response($recaptcha_v3, $captcha_response);
  if (!$verification_response['success']) {

    // If we here, then token verification failed.
    if ($verification_response['error-codes']) {
      $errors = [];
      $challenge = $recaptcha_v3
        ->getChallenge();
      if ($challenge === 'default') {
        $challenge = \Drupal::config('recaptcha_v3.settings')
          ->get('default_challenge');
      }
      foreach ($verification_response['error-codes'] as $code) {

        // If we have fallback challenge then do not log the threshold errors.
        if ($challenge && $code === 'score-threshold-not-met') {
          continue;
        }
        $errors[] = recaptcha_v3_error_by_code($code);
      }
      if ($errors) {
        $errors_string = implode(' ', $errors);
        \Drupal::logger('recaptcha_v3')
          ->error('Google reCAPTCHA v3 validation failed: @error', [
          '@error' => $errors_string,
        ]);
      }
    }
    $error_message = \Drupal::config('recaptcha_v3.settings')
      ->get('error_message');
  }

  // If captcha validated, then need to remove error related to the
  // captcha_response element. Otherwise, for example, if fallback is
  // captcha Math we will get error about exceeding input value length due to
  // recaptcha v3 response is much longer than allowed for Math captcha.
  // In another case if we have custom error message, then need to clear
  // all current 'captcha_response' element error messages either.
  if ($verification_response['success'] || !empty($error_message)) {
    $errors = $form_state
      ->getErrors();
    if (isset($errors['captcha_response'])) {
      $form_state
        ->clearErrors();
      foreach ($errors as $name => $error) {
        if ($name !== 'captcha_response') {
          $form_state
            ->setErrorByName($name, $error);
        }
      }
    }
  }
  if (!empty($error_message)) {
    $form_state
      ->setErrorByName('captcha_response', $error_message);
  }
  return (bool) $verification_response['success'];
}