Last active
October 17, 2018 00:57
-
-
Save gheydon/8938f9599c6760c0a32f44bd274cecbb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 540e70159b52ab3068a0c0b14ae0d770cd2f593a Mon Sep 17 00:00:00 2001 | |
From: Gordon Heydon <[email protected]> | |
Date: Wed, 17 Oct 2018 11:53:44 +1100 | |
Subject: [PATCH] Issue #2493183 by hswong3i, Jo Fitzgerald, rang501, | |
fearlsgroove, jedihe, bceyssens, james.williams, hass, ameymudras, | |
VitaliyB98, gregseb, maestrojed, akozma, alemadlei, goodDenis, RumyanaRuseva, | |
plov, ilya.no, janchojnacki, johnjw59, simon.fryer, recrit: Ajax support / | |
Use behaviors for 2.x | |
# Conflicts: | |
# recaptcha.module | |
# src/Tests/ReCaptchaBasicTest.php | |
--- | |
js/recaptcha.js | 34 ++++++++++++++++++++++++ | |
recaptcha.libraries.yml | 6 +++++ | |
recaptcha.module | 27 +++++++++++++++++--- | |
src/Tests/ReCaptchaBasicTest.php | 44 +++++++++++++++++++++++++++++--- | |
4 files changed, 105 insertions(+), 6 deletions(-) | |
create mode 100644 js/recaptcha.js | |
create mode 100644 recaptcha.libraries.yml | |
diff --git a/js/recaptcha.js b/js/recaptcha.js | |
new file mode 100644 | |
index 0000000..a9a5912 | |
--- /dev/null | |
+++ b/js/recaptcha.js | |
@@ -0,0 +1,34 @@ | |
+/** | |
+ * @file | |
+ * Contains the definition of the behaviour recaptcha. | |
+ */ | |
+ | |
+(function ($, Drupal) { | |
+ Drupal.behaviors.recaptcha = { | |
+ attach: function (context) { | |
+ $('.g-recaptcha', context).each(function () { | |
+ if (typeof grecaptcha === 'undefined' || typeof grecaptcha.render !== 'function') { | |
+ return; | |
+ } | |
+ if ($(this).closest('body').length > 0) { | |
+ if ($(this).hasClass('recaptcha-processed')) { | |
+ grecaptcha.reset(); | |
+ } | |
+ else { | |
+ grecaptcha.render(this, $(this).data()); | |
+ $(this).addClass('recaptcha-processed'); | |
+ } | |
+ } | |
+ }); | |
+ } | |
+ }; | |
+ | |
+ window.drupalRecaptchaOnload = function () { | |
+ $('.g-recaptcha').each(function () { | |
+ if (!$(this).hasClass('recaptcha-processed')) { | |
+ grecaptcha.render(this, $(this).data()); | |
+ $(this).addClass('recaptcha-processed'); | |
+ } | |
+ }); | |
+ }; | |
+})(jQuery, Drupal); | |
diff --git a/recaptcha.libraries.yml b/recaptcha.libraries.yml | |
new file mode 100644 | |
index 0000000..7471b37 | |
--- /dev/null | |
+++ b/recaptcha.libraries.yml | |
@@ -0,0 +1,6 @@ | |
+recaptcha: | |
+ js: | |
+ js/recaptcha.js: {} | |
+ dependencies: | |
+ - core/drupal | |
+ - core/jquery | |
diff --git a/recaptcha.module b/recaptcha.module | |
index 380854c..2ed5764 100644 | |
--- a/recaptcha.module | |
+++ b/recaptcha.module | |
@@ -86,6 +86,8 @@ function recaptcha_captcha($op, $captcha_type = '') { | |
'data-size' => $config->get('widget.size'), | |
'data-tabindex' => $config->get('widget.tabindex'), | |
]; | |
+ $captcha['form']['#attached']['library'][] = 'recaptcha/recaptcha'; | |
+ | |
// Filter out empty tabindex/size. | |
$attributes = array_filter($attributes); | |
@@ -98,7 +100,14 @@ function recaptcha_captcha($op, $captcha_type = '') { | |
[ | |
'#tag' => 'script', | |
'#attributes' => [ | |
- 'src' => Url::fromUri('https://www.google.com/recaptcha/api.js', ['query' => ['hl' => \Drupal::service('language_manager')->getCurrentLanguage()->getId()], 'absolute' => TRUE])->toString(), | |
+ 'src' => Url::fromUri($recaptcha_src, [ | |
+ 'query' => [ | |
+ 'hl' => \Drupal::service('language_manager')->getCurrentLanguage()->getId(), | |
+ 'onload' => 'drupalRecaptchaOnload', | |
+ 'render' => 'explicit', | |
+ ], | |
+ 'absolute' => TRUE, | |
+ ])->toString(), | |
'async' => TRUE, | |
'defer' => TRUE, | |
], | |
@@ -133,6 +142,12 @@ function recaptcha_captcha_validation($solution, $response, $element, $form_stat | |
// Use Drupal::httpClient() to circumvent all issues with the Google library. | |
$recaptcha = new \ReCaptcha\ReCaptcha($recaptcha_secret_key, new \ReCaptcha\RequestMethod\Drupal8Post()); | |
+ // Ensures the hostname matches. Required if "Domain Name Validation" is | |
+ // disabled for credentials. | |
+ if ($config->get('verify_hostname')) { | |
+ $recaptcha->setExpectedHostname($_SERVER['SERVER_NAME']); | |
+ } | |
+ | |
$resp = $recaptcha->verify( | |
$_POST['g-recaptcha-response'], | |
\Drupal::request()->getClientIp() | |
@@ -168,7 +183,13 @@ function recaptcha_captcha_validation($solution, $response, $element, $form_stat | |
* @see recaptcha-widget-noscript.tpl.php | |
*/ | |
function template_preprocess_recaptcha_widget_noscript(&$variables) { | |
- $variables['sitekey'] = $variables['widget']['sitekey']; | |
+ $variables['sitekey'] = $variables['widget']['sitekey']; | |
$variables['language'] = $variables['widget']['language']; | |
- $variables['url'] = Url::fromUri('https://www.google.com/recaptcha/api/fallback', ['query' => ['k' => $variables['widget']['sitekey'], 'hl' => $variables['widget']['language']], 'absolute' => TRUE])->toString(); | |
+ $variables['url'] = Url::fromUri($variables['widget']['recaptcha_src_fallback'], [ | |
+ 'query' => [ | |
+ 'k' => $variables['widget']['sitekey'], | |
+ 'hl' => $variables['widget']['language'], | |
+ ], | |
+ 'absolute' => TRUE, | |
+ ])->toString(); | |
} | |
diff --git a/src/Tests/ReCaptchaBasicTest.php b/src/Tests/ReCaptchaBasicTest.php | |
index 499bb3b..3200073 100644 | |
--- a/src/Tests/ReCaptchaBasicTest.php | |
+++ b/src/Tests/ReCaptchaBasicTest.php | |
@@ -129,15 +129,51 @@ class ReCaptchaBasicTest extends WebTestBase { | |
// Check if there is a reCAPTCHA on the login form. | |
$this->drupalGet('user/login'); | |
$this->assertRaw($grecaptcha, '[testReCaptchaOnLoginForm]: reCAPTCHA is shown on form.'); | |
- $this->assertRaw('<script src="https://www.google.com/recaptcha/api.js?hl=' . \Drupal::service('language_manager')->getCurrentLanguage()->getId() . '" async defer></script>', '[testReCaptchaOnLoginForm]: reCAPTCHA is shown on form.'); | |
+ $options = [ | |
+ 'query' => [ | |
+ 'hl' => \Drupal::service('language_manager')->getCurrentLanguage()->getId(), | |
+ 'onload' => 'drupalRecaptchaOnload', | |
+ 'render' => 'explicit', | |
+ ], | |
+ 'absolute' => TRUE, | |
+ ]; | |
+ $this->assertSession()->responseContains(Html::escape(Url::fromUri('https://www.google.com/recaptcha/api.js', $options)->toString()), '[testReCaptchaOnLoginForm]: reCAPTCHA is shown on form.'); | |
$this->assertNoRaw($grecaptcha . '<noscript>', '[testReCaptchaOnLoginForm]: NoScript code is not enabled for the reCAPTCHA.'); | |
// Test if the fall back url is properly build and noscript code added. | |
$this->config('recaptcha.settings')->set('widget.noscript', 1)->save(); | |
$this->drupalGet('user/login'); | |
- $this->assertRaw($grecaptcha . "\n" . '<noscript>', '[testReCaptchaOnLoginForm]: NoScript for reCAPTCHA is shown on form.'); | |
- $this->assertRaw('https://www.google.com/recaptcha/api/fallback?k=' . $site_key . '&hl=' . \Drupal::service('language_manager')->getCurrentLanguage()->getId(), '[testReCaptchaOnLoginForm]: Fallback URL with IFRAME has been found.'); | |
+ $this->assertSession()->responseContains($grecaptcha . "\n" . '<noscript>', '[testReCaptchaOnLoginForm]: NoScript for reCAPTCHA is shown on form.'); | |
+ $options = [ | |
+ 'query' => [ | |
+ 'k' => $site_key, | |
+ 'hl' => \Drupal::service('language_manager')->getCurrentLanguage()->getId(), | |
+ ], | |
+ 'absolute' => TRUE, | |
+ ]; | |
+ $this->assertSession()->responseContains(Html::escape(Url::fromUri('https://www.google.com/recaptcha/api/fallback', $options)->toString()), '[testReCaptchaOnLoginForm]: Fallback URL with IFRAME has been found.'); | |
+ | |
+ // Check if there is a reCAPTCHA with global url on the login form. | |
+ $this->config('recaptcha.settings')->set('use_globally', TRUE)->save(); | |
+ $this->drupalGet('user/login'); | |
+ $options = [ | |
+ 'query' => [ | |
+ 'hl' => \Drupal::service('language_manager')->getCurrentLanguage()->getId(), | |
+ 'onload' => 'drupalRecaptchaOnload', | |
+ 'render' => 'explicit', | |
+ ], | |
+ 'absolute' => TRUE, | |
+ ]; | |
+ $this->assertSession()->responseContains(Html::escape(Url::fromUri('https://www.recaptcha.net/recaptcha/api.js', $options)->toString()), '[testReCaptchaOnLoginForm]: Global reCAPTCHA is shown on form.'); | |
+ $options = [ | |
+ 'query' => [ | |
+ 'k' => $site_key, | |
+ 'hl' => \Drupal::service('language_manager')->getCurrentLanguage()->getId(), | |
+ ], | |
+ 'absolute' => TRUE, | |
+ ]; | |
+ $this->assertSession()->responseContains(Html::escape(Url::fromUri('https://www.recaptcha.net/recaptcha/api/fallback', $options)->toString()), '[testReCaptchaOnLoginForm]: Global fallback URL with IFRAME has been found.'); | |
// Check that data-size attribute does not exists. | |
$this->config('recaptcha.settings')->set('widget.size', '')->save(); | |
@@ -166,6 +202,8 @@ class ReCaptchaBasicTest extends WebTestBase { | |
// Try to log in, which should fail. | |
$edit['name'] = $this->normal_user->getUsername(); | |
$edit['pass'] = $this->normal_user->getPassword(); | |
+ $this->assertSession()->responseContains('captcha_response'); | |
+ $this->assertSession() | |
$edit['captcha_response'] = '?'; | |
$this->drupalPostForm('user/login', $edit, t('Log in')); | |
-- | |
2.19.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment