Skip to content

Commit

Permalink
Implement Invisible Recaptcha (#18146)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rene Pasing authored and Michael Babker committed Aug 28, 2018
1 parent 6d1e90f commit 9a12f28
Show file tree
Hide file tree
Showing 50 changed files with 1,716 additions and 352 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Expand Up @@ -69,6 +69,14 @@ Desktop.ini
# Extra files installed by Composer not needed in the CMS environment
# This should only ignore files like unit testing or READMEs, production
# code must remain to ensure all libraries properly function
/libraries/vendor/google/recaptcha/examples
/libraries/vendor/google/recaptcha/tests
/libraries/vendor/google/recaptcha/.gitignore
/libraries/vendor/google/recaptcha/.travis.yml
/libraries/vendor/google/recaptcha/composer.json
/libraries/vendor/google/recaptcha/CONTRIBUTING.md
/libraries/vendor/google/recaptcha/phpunit.xml.dist
/libraries/vendor/google/recaptcha/README.md
/libraries/vendor/ircmaxell/password-compat/test
/libraries/vendor/ircmaxell/password-compat/.travis.yml
/libraries/vendor/ircmaxell/password-compat/composer.json
Expand Down
1 change: 1 addition & 0 deletions administrator/components/com_admin/script.php
Expand Up @@ -1973,6 +1973,7 @@ public function deleteUnexistingFiles()
* Joomla! 3.8.0 thru 3.9.0
*/
'/libraries/src/Mail/language/phpmailer.lang-joomla.php',
'/plugins/captcha/recaptcha/recaptchalib.php',

/*
* Legacy FOF
Expand Down
@@ -0,0 +1,2 @@
INSERT INTO `#__extensions` (`extension_id`, `package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES
(494, 0, 'plg_captcha_recaptcha_invisible', 'plugin', 'recaptcha_invisible', 'captcha', 0, 0, 1, 0, '', '{"public_key":"","private_key":"","theme":"clean"}', '', '', 0, '0000-00-00 00:00:00', 0, 0);
@@ -0,0 +1,2 @@
INSERT INTO "#__extensions" ("extension_id", "package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES
(494, 0, 'plg_captcha_recaptcha_invisible', 'plugin', 'recaptcha_invisible', 'captcha', 0, 0, 1, 0, '', '{"public_key":"","private_key":"","theme":"clean"}', '', '', 0, '1970-01-01 00:00:00', 0, 0);
@@ -0,0 +1,2 @@
INSERT INTO "#__extensions" ("extension_id", "package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES
(494, 0, 'plg_captcha_recaptcha_invisible', 'plugin', 'recaptcha_invisible', 'captcha', 0, 0, 1, 0, '', '{"public_key":"","private_key":"","theme":"clean"}', '', '', 0, '1900-01-01 00:00:00', 0, 0);
8 changes: 8 additions & 0 deletions administrator/language/en-GB/en-GB.plg_captcha_recaptcha.ini
Expand Up @@ -35,6 +35,14 @@ PLG_RECAPTCHA_SIZE_LABEL="Size"
PLG_RECAPTCHA_SIZE_DESC="Select the size for the reCAPTCHA field."
PLG_RECAPTCHA_THEME_NORMAL="Normal"
PLG_RECAPTCHA_THEME_COMPACT="Compact"
PLG_RECAPTCHA_TABINDEX_LABEL="Tabindex"
PLG_RECAPTCHA_TABINDEX_DESC="The tabindex of the reCAPTCHA widget"
PLG_RECAPTCHA_CALLBACK_LABEL="Callback"
PLG_RECAPTCHA_CALLBACK_DESC="(Optional) JavaScript callback, executed after successful reCAPTCHA response"
PLG_RECAPTCHA_EXPIRED_CALLBACK_LABEL="Expired callback"
PLG_RECAPTCHA_EXPIRED_CALLBACK_DESC="(Optional) JavaScript callback, executed when the reCAPTCHA expired"
PLG_RECAPTCHA_EXPIRED_CALLBACK_LABEL="Error callback"
PLG_RECAPTCHA_EXPIRED_CALLBACK_DESC="(Optional) JavaScript callback, executed when the reCAPTCHA encounters an error"

; Error messages
PLG_RECAPTCHA_ERROR_NO_PRIVATE_KEY="reCAPTCHA plugin needs a secret key to be set in its parameters. Please contact a site administrator."
Expand Down
Expand Up @@ -3,5 +3,5 @@
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

PLG_CAPTCHA_RECAPTCHA_XML_DESCRIPTION="This CAPTCHA plugin uses the reCAPTCHA service to prevent spammers while it helps to digitize books, newspapers and old radio shows. To get a site and secret key for your domain, go to https://www.google.com/recaptcha. To use this for new account registration, go to Options in the User Manager and select Captcha - reCaptcha as the Captcha."
PLG_CAPTCHA_RECAPTCHA="Captcha - ReCaptcha"
PLG_CAPTCHA_RECAPTCHA_XML_DESCRIPTION="This CAPTCHA plugin uses the reCAPTCHA service to prevent spammers while it helps to digitize books, newspapers and old radio shows. To get a site and secret key for your domain, go to <a href="_QQ_"https://www.google.com/recaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://www.google.com/recaptcha</a>. To use this for new account registration, go to Options in the User Manager and select CAPTCHA - reCAPTCHA as the CAPTCHA."
PLG_CAPTCHA_RECAPTCHA="CAPTCHA - reCAPTCHA"
@@ -0,0 +1,32 @@
; Joomla! Project
; Copyright (C) 2005 - 2017 Open Source Matters. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

PLG_CAPTCHA_RECAPTCHA_INVISIBLE_XML_DESCRIPTION="This CAPTCHA plugin uses the Invisible reCAPTCHA service. To get a site and secret key for your domain, go to <a href="_QQ_"https://www.google.com/recaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://www.google.com/recaptcha</a>."
PLG_CAPTCHA_RECAPTCHA_INVISIBLE="CAPTCHA - Invisible reCAPTCHA "

; Params
PLG_RECAPTCHA_INVISIBLE_PUBLIC_KEY_LABEL="Site Key"
PLG_RECAPTCHA_INVISIBLE_PUBLIC_KEY_DESC="Used in the JavaScript code that is served to your users."
PLG_RECAPTCHA_INVISIBLE_PRIVATE_KEY_LABEL="Secret Key"
PLG_RECAPTCHA_INVISIBLE_PRIVATE_KEY_DESC="Used in the communication between your server and the reCAPTCHA server. Be sure to keep it a secret."
PLG_RECAPTCHA_INVISIBLE_BADGE_LABEL="Badge"
PLG_RECAPTCHA_INVISIBLE_BADGE_DESC="Positioning of the reCAPTCHA badge."
PLG_RECAPTCHA_INVISIBLE_BADGE_BOTTOMRIGHT="Bottom right"
PLG_RECAPTCHA_INVISIBLE_BADGE_BOTTOMLEFT="Bottom left"
PLG_RECAPTCHA_INVISIBLE_BADGE_INLINE="Inline"
PLG_RECAPTCHA_INVISIBLE_TABINDEX_LABEL="Tabindex"
PLG_RECAPTCHA_INVISIBLE_TABINDEX_DESC="The tabindex of the challenge."
PLG_RECAPTCHA_INVISIBLE_CALLBACK_LABEL="Callback"
PLG_RECAPTCHA_INVISIBLE_CALLBACK_DESC="(Optional) JavaScript callback, executed after successful reCAPTCHA response"
PLG_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_LABEL="Expired callback"
PLG_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_DESC="(Optional) JavaScript callback, executed when the reCAPTCHA expired"
PLG_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_LABEL="Error callback"
PLG_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_DESC="(Optional) JavaScript callback, executed when the reCAPTCHA encounters an error"

; Error messages
PLG_RECAPTCHA_INVISIBLE_ERROR_NO_PRIVATE_KEY="reCAPTCHA plugin needs a secret key to be set in its parameters. Please contact a site administrator."
PLG_RECAPTCHA_INVISIBLE_ERROR_NO_PUBLIC_KEY="reCAPTCHA plugin needs a site key to be set in its parameters. Please contact a site administrator."
PLG_RECAPTCHA_INVISIBLE_ERROR_EMPTY_SOLUTION="Empty solution not allowed."
PLG_RECAPTCHA_INVISIBLE_ERROR_NO_IP="For security reasons, you must pass the remote IP address to reCAPTCHA."
@@ -0,0 +1,7 @@
; Joomla! Project
; Copyright (C) 2005 - 2017 Open Source Matters. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

PLG_CAPTCHA_RECAPTCHA_INVISIBLE_XML_DESCRIPTION="This CAPTCHA plugin uses the Invisible reCAPTCHA service. To get a site and secret key for your domain, go to <a href="_QQ_"https://www.google.com/recaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://www.google.com/recaptcha</a>."
PLG_CAPTCHA_RECAPTCHA_INVISIBLE="CAPTCHA - Invisible reCAPTCHA "
60 changes: 60 additions & 0 deletions components/com_users/layouts/joomla/form/renderfield.php
@@ -0,0 +1,60 @@
<?php
/**
* @package Joomla.Site
* @subpackage Layout
*
* @copyright Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

defined('JPATH_BASE') or die;

extract($displayData);

/**
* Layout variables
* ---------------------
* $options : (array) Optional parameters
* $label : (string) The html code for the label (not required if $options['hiddenLabel'] is true)
* $input : (string) The input field html code
*/

if (!empty($options['showonEnabled']))
{
JHtml::_('jquery.framework');
JHtml::_('script', 'jui/cms.js', array('version' => 'auto', 'relative' => true));
}

$class = empty($options['class']) ? '' : ' ' . $options['class'];
$rel = empty($options['rel']) ? '' : ' ' . $options['rel'];

/**
* @TODO:
*
* As mentioned in #8473 (https://github.com/joomla/joomla-cms/pull/8473), ...
* as long as we cannot access the field properties properly, this seems to
* be the way to go for now.
*
* On a side note: Parsing html is seldom a good idea.
* https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454
*/
preg_match('/class=\"([^\"]+)\"/i', $input, $match);

$required = (strpos($input, 'aria-required="true"') !== false || (!empty($match[1]) && strpos($match[1], 'required') !== false));
$typeOfSpacer = (strpos($label, 'spacer-lbl') !== false);

?>

<div class="control-group<?php echo $class; ?>"<?php echo $rel; ?>>
<?php if (empty($options['hiddenLabel'])): ?>
<div class="control-label">
<?php echo $label; ?>
<?php if (!$required && !$typeOfSpacer) : ?>
<span class="optional"><?php echo JText::_('COM_USERS_OPTIONAL'); ?></span>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="controls">
<?php echo $input; ?>
</div>
</div>
22 changes: 2 additions & 20 deletions components/com_users/views/login/tmpl/default_login.php
Expand Up @@ -35,27 +35,9 @@
<?php endif; ?>
<form action="<?php echo JRoute::_('index.php?option=com_users&task=user.login'); ?>" method="post" class="form-validate form-horizontal well">
<fieldset>
<?php foreach ($this->form->getFieldset('credentials') as $field) : ?>
<?php if (!$field->hidden) : ?>
<div class="control-group">
<div class="control-label">
<?php echo $field->label; ?>
</div>
<div class="controls">
<?php echo $field->input; ?>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
<?php echo $this->form->renderFieldset('credentials'); ?>
<?php if ($this->tfa) : ?>
<div class="control-group">
<div class="control-label">
<?php echo $this->form->getField('secretkey')->label; ?>
</div>
<div class="controls">
<?php echo $this->form->getField('secretkey')->input; ?>
</div>
</div>
<?php echo $this->form->renderField('secretkey'); ?>
<?php endif; ?>
<?php if (JPluginHelper::isEnabled('system', 'remember')) : ?>
<div class="control-group">
Expand Down
20 changes: 1 addition & 19 deletions components/com_users/views/registration/tmpl/default.php
Expand Up @@ -29,25 +29,7 @@
<?php if (isset($fieldset->label)) : ?>
<legend><?php echo JText::_($fieldset->label); ?></legend>
<?php endif; ?>
<?php // Iterate through the fields in the set and display them. ?>
<?php foreach ($fields as $field) : ?>
<?php // If the field is hidden, just display the input. ?>
<?php if ($field->hidden) : ?>
<?php echo $field->input; ?>
<?php else : ?>
<div class="control-group">
<div class="control-label">
<?php echo $field->label; ?>
<?php if (!$field->required && $field->type !== 'Spacer') : ?>
<span class="optional"><?php echo JText::_('COM_USERS_OPTIONAL'); ?></span>
<?php endif; ?>
</div>
<div class="controls">
<?php echo $field->input; ?>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
<?php echo $this->form->renderFieldset($fieldset->name); ?>
</fieldset>
<?php endif; ?>
<?php endforeach; ?>
Expand Down
17 changes: 4 additions & 13 deletions components/com_users/views/remind/tmpl/default.php
Expand Up @@ -24,19 +24,10 @@
<form id="user-registration" action="<?php echo JRoute::_('index.php?option=com_users&task=remind.remind'); ?>" method="post" class="form-validate form-horizontal well">
<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
<fieldset>
<p><?php echo JText::_($fieldset->label); ?></p>
<?php foreach ($this->form->getFieldset($fieldset->name) as $name => $field) : ?>
<?php if ($field->hidden === false) : ?>
<div class="control-group">
<div class="control-label">
<?php echo $field->label; ?>
</div>
<div class="controls">
<?php echo $field->input; ?>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
<?php if (isset($fieldset->label)) : ?>
<p><?php echo JText::_($fieldset->label); ?></p>
<?php endif; ?>
<?php echo $this->form->renderFieldset($fieldset->name); ?>
</fieldset>
<?php endforeach; ?>
<div class="control-group">
Expand Down
15 changes: 4 additions & 11 deletions components/com_users/views/reset/tmpl/complete.php
Expand Up @@ -24,17 +24,10 @@
<form action="<?php echo JRoute::_('index.php?option=com_users&task=reset.complete'); ?>" method="post" class="form-validate form-horizontal well">
<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
<fieldset>
<p><?php echo JText::_($fieldset->label); ?></p>
<?php foreach ($this->form->getFieldset($fieldset->name) as $name => $field) : ?>
<div class="control-group">
<div class="control-label">
<?php echo $field->label; ?>
</div>
<div class="controls">
<?php echo $field->input; ?>
</div>
</div>
<?php endforeach; ?>
<?php if (isset($fieldset->label)) : ?>
<p><?php echo JText::_($fieldset->label); ?></p>
<?php endif; ?>
<?php echo $this->form->renderFieldset($fieldset->name); ?>
</fieldset>
<?php endforeach; ?>
<div class="control-group">
Expand Down
15 changes: 4 additions & 11 deletions components/com_users/views/reset/tmpl/confirm.php
Expand Up @@ -24,17 +24,10 @@
<form action="<?php echo JRoute::_('index.php?option=com_users&task=reset.confirm'); ?>" method="post" class="form-validate form-horizontal well">
<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
<fieldset>
<p><?php echo JText::_($fieldset->label); ?></p>
<?php foreach ($this->form->getFieldset($fieldset->name) as $name => $field) : ?>
<div class="control-group">
<div class="control-label">
<?php echo $field->label; ?>
</div>
<div class="controls">
<?php echo $field->input; ?>
</div>
</div>
<?php endforeach; ?>
<?php if (isset($fieldset->label)) : ?>
<p><?php echo JText::_($fieldset->label); ?></p>
<?php endif; ?>
<?php echo $this->form->renderFieldset($fieldset->name); ?>
</fieldset>
<?php endforeach; ?>
<div class="control-group">
Expand Down
17 changes: 4 additions & 13 deletions components/com_users/views/reset/tmpl/default.php
Expand Up @@ -24,19 +24,10 @@
<form id="user-registration" action="<?php echo JRoute::_('index.php?option=com_users&task=reset.request'); ?>" method="post" class="form-validate form-horizontal well">
<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
<fieldset>
<p><?php echo JText::_($fieldset->label); ?></p>
<?php foreach ($this->form->getFieldset($fieldset->name) as $name => $field) : ?>
<?php if ($field->hidden === false) : ?>
<div class="control-group">
<div class="control-label">
<?php echo $field->label; ?>
</div>
<div class="controls">
<?php echo $field->input; ?>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
<?php if (isset($fieldset->label)) : ?>
<p><?php echo JText::_($fieldset->label); ?></p>
<?php endif; ?>
<?php echo $this->form->renderFieldset($fieldset->name); ?>
</fieldset>
<?php endforeach; ?>
<div class="control-group">
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -43,7 +43,8 @@
"symfony/polyfill-php56": "~1.0",
"symfony/polyfill-php73": "~1.8",
"symfony/yaml": "2.*",
"simplepie/simplepie": "1.3.1"
"simplepie/simplepie": "1.3.1",
"google/recaptcha": "^1.1"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35",
Expand Down
47 changes: 46 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions installation/sql/mysql/joomla.sql
Expand Up @@ -666,6 +666,7 @@ INSERT INTO `#__extensions` (`extension_id`, `package_id`, `name`, `type`, `elem
(491, 0, 'plg_privacy_content', 'plugin', 'content', 'privacy', 0, 1, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(492, 0, 'plg_privacy_message', 'plugin', 'message', 'privacy', 0, 1, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(493, 0, 'plg_privacy_actionlogs', 'plugin', 'actionlogs', 'privacy', 0, 0, 1, 0, '', '{}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(494, 0, 'plg_captcha_recaptcha_invisible', 'plugin', 'recaptcha_invisible', 'captcha', 0, 0, 1, 0, '', '{"public_key":"","private_key":"","theme":"clean"}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(503, 0, 'beez3', 'template', 'beez3', '', 0, 1, 1, 0, '', '{"wrapperSmall":"53","wrapperLarge":"72","sitetitle":"","sitedescription":"","navposition":"center","templatecolor":"nature"}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(504, 0, 'hathor', 'template', 'hathor', '', 1, 1, 1, 0, '', '{"showSiteName":"0","colourChoice":"0","boldText":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(506, 0, 'protostar', 'template', 'protostar', '', 0, 1, 1, 0, '', '{"templateColor":"","logoFile":"","googleFont":"1","googleFontName":"Open+Sans","fluidContainer":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
Expand Down
1 change: 1 addition & 0 deletions installation/sql/postgresql/joomla.sql
Expand Up @@ -679,6 +679,7 @@ INSERT INTO "#__extensions" ("extension_id", "package_id", "name", "type", "elem
(491, 0, 'plg_privacy_content', 'plugin', 'content', 'privacy', 0, 1, 1, 0, '', '{}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(492, 0, 'plg_privacy_message', 'plugin', 'message', 'privacy', 0, 1, 1, 0, '', '{}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(493, 0, 'plg_privacy_actionlogs', 'plugin', 'actionlogs', 'privacy', 0, 0, 1, 0, '', '{}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(494, 0, 'plg_captcha_recaptcha_invisible', 'plugin', 'recaptcha_invisible', 'captcha', 0, 0, 1, 0, '', '{"public_key":"","private_key":"","theme":"clean"}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(503, 0, 'beez3', 'template', 'beez3', '', 0, 1, 1, 0, '', '{"wrapperSmall":"53","wrapperLarge":"72","sitetitle":"","sitedescription":"","navposition":"center","templatecolor":"nature"}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(504, 0, 'hathor', 'template', 'hathor', '', 1, 1, 1, 0, '', '{"showSiteName":"0","colourChoice":"0","boldText":"0"}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(506, 0, 'protostar', 'template', 'protostar', '', 0, 1, 1, 0, '', '{"templateColor":"","logoFile":"","googleFont":"1","googleFontName":"Open+Sans","fluidContainer":"0"}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
Expand Down

0 comments on commit 9a12f28

Please sign in to comment.