Skip to content

Instantly share code, notes, and snippets.

@gheydon
Last active October 17, 2018 00:57
Show Gist options
  • Save gheydon/8938f9599c6760c0a32f44bd274cecbb to your computer and use it in GitHub Desktop.
Save gheydon/8938f9599c6760c0a32f44bd274cecbb to your computer and use it in GitHub Desktop.
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 . '&amp;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