diff --git a/administrator/language/en-GB/en-GB.plg_captcha_recaptcha.ini b/administrator/language/en-GB/en-GB.plg_captcha_recaptcha.ini
index 6ba182347e565..326d46f199fa3 100644
--- a/administrator/language/en-GB/en-GB.plg_captcha_recaptcha.ini
+++ b/administrator/language/en-GB/en-GB.plg_captcha_recaptcha.ini
@@ -3,47 +3,37 @@
; 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 public and private key for your domain, go to http://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_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 http://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"
; Params
-PLG_RECAPTCHA_PUBLIC_KEY_LABEL="Public Key"
-PLG_RECAPTCHA_PUBLIC_KEY_DESC="Used in the JavaScript code that is served to your users. See the plugin description for instructions on getting a public key."
-PLG_RECAPTCHA_PRIVATE_KEY_LABEL="Private Key"
-PLG_RECAPTCHA_PRIVATE_KEY_DESC="Used in the communication between your server and the ReCaptha server. Be sure to keep it a secret. See the plugin description for instructions on getting a private key."
+PLG_RECAPTCHA_PUBLIC_KEY_LABEL="Site key"
+PLG_RECAPTCHA_PUBLIC_KEY_DESC="Used in the JavaScript code that is served to your users. See the plugin description for instructions on getting a site key."
+PLG_RECAPTCHA_PRIVATE_KEY_LABEL="Secret key"
+PLG_RECAPTCHA_PRIVATE_KEY_DESC="Used in the communication between your server and the ReCaptha server. Be sure to keep it a secret. See the plugin description for instructions on getting a secret key."
PLG_RECAPTCHA_THEME_LABEL="Theme"
PLG_RECAPTCHA_THEME_DESC="Defines which theme to use for reCAPTCHA."
+PLG_RECAPTCHA_THEME_LIGHT="Light"
+PLG_RECAPTCHA_THEME_DARK="Dark"
+
+; 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."
+PLG_RECAPTCHA_ERROR_NO_PUBLIC_KEY="ReCaptcha plugin needs a site key to be set in its parameters. Please contact a site administrator."
+PLG_RECAPTCHA_ERROR_NOT_SET="Please complete the security question."
+PLG_RECAPTCHA_ERROR_NO_IP="For security reasons, you must pass the remote ip address to reCAPTCHA"
+
+; Deprecated: No longer used
PLG_RECAPTCHA_THEME_RED="Red"
PLG_RECAPTCHA_THEME_WHITE="White"
PLG_RECAPTCHA_THEME_BLACKGLASS="BlackGlass"
PLG_RECAPTCHA_THEME_CLEAN="Clean"
PLG_RECAPTCHA_LANG_LABEL="Language"
PLG_RECAPTCHA_LANG_DESC="Select the language for the reCAPTCHA. If default is set and the language file has a custom translation, it will be used."
-
-; Error messages
-PLG_RECAPTCHA_ERROR_NO_PRIVATE_KEY="ReCaptcha plugin needs a private key to be set in its parameters. Please contact a site administrator."
-PLG_RECAPTCHA_ERROR_NO_PUBLIC_KEY="ReCaptcha plugin needs a public key to be set in its parameters. Please contact a site administrator."
PLG_RECAPTCHA_ERROR_EMPTY_SOLUTION="Empty solution not allowed."
-PLG_RECAPTCHA_ERROR_NO_IP="For security reasons, you must pass the remote ip address to reCAPTCHA"
-PLG_RECAPTCHA_ERROR_UNKNOWN="Unknown error."
-PLG_RECAPTCHA_ERROR_INVALID_SITE_PUBLIC_KEY="We weren't able to verify the public key."
-PLG_RECAPTCHA_ERROR_INVALID_SITE_PRIVATE_KEY="We weren't able to verify the private key."
+PLG_RECAPTCHA_ERROR_INVALID_SITE_PUBLIC_KEY="We weren't able to verify the site key."
+PLG_RECAPTCHA_ERROR_INVALID_SITE_PRIVATE_KEY="We weren't able to verify the secret key."
PLG_RECAPTCHA_ERROR_INVALID_REQUEST_COOKIE="The challenge parameter of the verify script was incorrect."
PLG_RECAPTCHA_ERROR_INCORRECT_CAPTCHA_SOL="The CAPTCHA solution was incorrect."
PLG_RECAPTCHA_ERROR_VERIFY_PARAMS_INCORRECT="The parameters to verify were incorrect, make sure you are passing all the required parameters."
PLG_RECAPTCHA_ERROR_INVALID_REFERRER="reCAPTCHA API keys are tied to a specific domain name for security reasons."
PLG_RECAPTCHA_ERROR_RECAPTCHA_NOT_REACHABLE="Unable to contact the reCAPTCHA verify server."
-
-; Uncomment(remove the ";" from the beginning of the line) the following lines if reCAPTCHA is not available in your language
-; When uncommenting, do NOT translate PLG_RECAPTCHA_CUSTOM_LANG
-; As of 01/01/2012, the following languages do not need translation: en, nl, fr, de, pt, ru, es, tr
-;PLG_RECAPTCHA_CUSTOM_LANG="true"
-;PLG_RECAPTCHA_INSTRUCTIONS_VISUAL="Type the two words:"
-;PLG_RECAPTCHA_INSTRUCTIONS_AUDIO="Type what you hear:"
-;PLG_RECAPTCHA_PLAY_AGAIN="Play sound again"
-;PLG_RECAPTCHA_CANT_HEAR_THIS="Download sound as MP3"
-;PLG_RECAPTCHA_VISUAL_CHALLENGE="Get a visual challenge"
-;PLG_RECAPTCHA_AUDIO_CHALLENGE="Get an audio challenge"
-;PLG_RECAPTCHA_REFRESH_BTN="Get a new challenge"
-;PLG_RECAPTCHA_HELP_BTN="Help"
-;PLG_RECAPTCHA_INCORRECT_TRY_AGAIN="Incorrect. Try again."
diff --git a/plugins/captcha/recaptcha/recaptcha.php b/plugins/captcha/recaptcha/recaptcha.php
index 65d33f9e28da9..d3c54238ff31f 100644
--- a/plugins/captcha/recaptcha/recaptcha.php
+++ b/plugins/captcha/recaptcha/recaptcha.php
@@ -17,10 +17,6 @@
*/
class PlgCaptchaRecaptcha extends JPlugin
{
- const RECAPTCHA_API_SERVER = "http://www.google.com/recaptcha/api";
- const RECAPTCHA_API_SECURE_SERVER = "https://www.google.com/recaptcha/api";
- const RECAPTCHA_VERIFY_SERVER = "www.google.com";
-
/**
* Load the language file on instantiation.
*
@@ -34,37 +30,33 @@ class PlgCaptchaRecaptcha extends JPlugin
*
* @param string $id The id of the field.
*
- * @return Boolean True on success, false otherwise
+ * @return Boolean True on success, false otherwise
*
* @since 2.5
*/
public function onInit($id = 'dynamic_recaptcha_1')
{
$document = JFactory::getDocument();
- $app = JFactory::getApplication();
+ $app = JFactory::getApplication();
JHtml::_('jquery.framework');
- $lang = $this->_getLanguage();
- $pubkey = $this->params->get('public_key', '');
- $theme = $this->params->get('theme', 'clean');
+ $public_key = $this->params->get('public_key', '');
+ $theme = $this->params->get('theme', 'light');
- if ($pubkey == null || $pubkey == '')
+ if ($public_key == null || $public_key == '')
{
throw new Exception(JText::_('PLG_RECAPTCHA_ERROR_NO_PUBLIC_KEY'));
}
- $server = self::RECAPTCHA_API_SERVER;
+ $file = $app->isSSLConnection() ? 'https' : 'http';
+ $file .= '://www.google.com/recaptcha/api.js?hl=' . JFactory::getLanguage()->getTag() . '&onload=onloadCallback&render=explicit';
- if ($app->isSSLConnection())
- {
- $server = self::RECAPTCHA_API_SECURE_SERVER;
- }
+ JHtml::_('script', $file, true, true);
- JHtml::_('script', $server . '/js/recaptcha_ajax.js');
- $document->addScriptDeclaration('jQuery( document ).ready(function()
- {
- Recaptcha.create("' . $pubkey . '", "' . $id . '", {theme: "' . $theme . '",' . $lang . 'tabindex: 0});});'
+ $document->addScriptDeclaration('var onloadCallback = function() {'
+ . 'grecaptcha.render("' . $id . '", {sitekey: "' . $public_key . '", theme: "' . $theme . '"});'
+ . '}'
);
return true;
@@ -98,11 +90,10 @@ public function onDisplay($name, $id = 'dynamic_recaptcha_1', $class = '')
*/
public function onCheckAnswer($code)
{
- $input = JFactory::getApplication()->input;
+ $input = JFactory::getApplication()->input;
$privatekey = $this->params->get('private_key');
- $remoteip = $input->server->get('REMOTE_ADDR', '', 'string');
- $challenge = $input->get('recaptcha_challenge_field', '', 'string');
- $response = $input->get('recaptcha_response_field', '', 'string');
+ $remoteip = $input->server->get('REMOTE_ADDR', '', 'string');
+ $response = $input->get('g-recaptcha-response', '', 'string');
// Check for Private Key
if (empty($privatekey))
@@ -121,147 +112,28 @@ public function onCheckAnswer($code)
}
// Discard spam submissions
- if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0)
+ if ($response == null || strlen($response) == 0)
{
$this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_EMPTY_SOLUTION'));
return false;
}
- $response = $this->_recaptcha_http_post(
- self::RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
- array(
- 'privatekey' => $privatekey,
- 'remoteip' => $remoteip,
- 'challenge' => $challenge,
- 'response' => $response
- )
- );
+ require_once 'recaptchalib.php';
+ $reCaptcha = new ReCaptcha($privatekey);
+ $response = $reCaptcha->verifyResponse($remoteip, $response);
- $answers = explode("\n", $response[1]);
-
- if (trim($answers[0]) == 'true')
- {
- return true;
- }
- else
+ if (!isset($response->success) || !$response->success)
{
// @todo use exceptions here
- $this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_' . strtoupper(str_replace('-', '_', $answers[1]))));
+ foreach ($response->errorCodes as $error)
+ {
+ $this->_subject->setError($error);
+ }
return false;
}
- }
-
- /**
- * Encodes the given data into a query string format.
- *
- * @param array $data Array of string elements to be encoded
- *
- * @return string Encoded request
- *
- * @since 2.5
- */
- private function _recaptcha_qsencode($data)
- {
- $req = "";
-
- foreach ($data as $key => $value)
- {
- $req .= $key . '=' . urlencode(stripslashes($value)) . '&';
- }
-
- // Cut the last '&'
- $req = rtrim($req, '&');
-
- return $req;
- }
- /**
- * Submits an HTTP POST to a reCAPTCHA server.
- *
- * @param string $host Host name to POST to.
- * @param string $path Path on host to POST to.
- * @param array $data Data to be POSTed.
- * @param int $port Optional port number on host.
- *
- * @return array Response
- *
- * @since 2.5
- */
- private function _recaptcha_http_post($host, $path, $data, $port = 80)
- {
- $req = $this->_recaptcha_qsencode($data);
-
- $http_request = "POST $path HTTP/1.0\r\n";
- $http_request .= "Host: $host\r\n";
- $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
- $http_request .= "Content-Length: " . strlen($req) . "\r\n";
- $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
- $http_request .= "\r\n";
- $http_request .= $req;
-
- $response = '';
-
- if (($fs = @fsockopen($host, $port, $errno, $errstr, 10)) == false )
- {
- die('Could not open socket');
- }
-
- fwrite($fs, $http_request);
-
- while (!feof($fs))
- {
- // One TCP-IP packet
- $response .= fgets($fs, 1160);
- }
-
- fclose($fs);
- $response = explode("\r\n\r\n", $response, 2);
-
- return $response;
- }
-
- /**
- * Get the language tag or a custom translation
- *
- * @return string
- *
- * @since 2.5
- */
- private function _getLanguage()
- {
- $language = JFactory::getLanguage();
-
- $tag = explode('-', $language->getTag());
- $tag = $tag[0];
- $available = array('en', 'pt', 'fr', 'de', 'nl', 'ru', 'es', 'tr');
-
- if (in_array($tag, $available))
- {
- return "lang : '" . $tag . "',";
- }
-
- // If the default language is not available, let's search for a custom translation
- if ($language->hasKey('PLG_RECAPTCHA_CUSTOM_LANG'))
- {
- $custom[] = 'custom_translations : {';
- $custom[] = "\t" . 'instructions_visual : "' . JText::_('PLG_RECAPTCHA_INSTRUCTIONS_VISUAL') . '",';
- $custom[] = "\t" . 'instructions_audio : "' . JText::_('PLG_RECAPTCHA_INSTRUCTIONS_AUDIO') . '",';
- $custom[] = "\t" . 'play_again : "' . JText::_('PLG_RECAPTCHA_PLAY_AGAIN') . '",';
- $custom[] = "\t" . 'cant_hear_this : "' . JText::_('PLG_RECAPTCHA_CANT_HEAR_THIS') . '",';
- $custom[] = "\t" . 'visual_challenge : "' . JText::_('PLG_RECAPTCHA_VISUAL_CHALLENGE') . '",';
- $custom[] = "\t" . 'audio_challenge : "' . JText::_('PLG_RECAPTCHA_AUDIO_CHALLENGE') . '",';
- $custom[] = "\t" . 'refresh_btn : "' . JText::_('PLG_RECAPTCHA_REFRESH_BTN') . '",';
- $custom[] = "\t" . 'help_btn : "' . JText::_('PLG_RECAPTCHA_HELP_BTN') . '",';
- $custom[] = "\t" . 'incorrect_try_again : "' . JText::_('PLG_RECAPTCHA_INCORRECT_TRY_AGAIN') . '",';
- $custom[] = '},';
- $custom[] = "lang : '" . $tag . "',";
-
- return implode("\n", $custom);
- }
-
- // If nothing helps fall back to english
- return '';
+ return true;
}
}
diff --git a/plugins/captcha/recaptcha/recaptcha.xml b/plugins/captcha/recaptcha/recaptcha.xml
index 2cda724bdb391..9f84145355ac4 100644
--- a/plugins/captcha/recaptcha/recaptcha.xml
+++ b/plugins/captcha/recaptcha/recaptcha.xml
@@ -39,19 +39,15 @@
+ value="light">PLG_RECAPTCHA_THEME_LIGHT
-
-
+ value="dark">PLG_RECAPTCHA_THEME_DARK
diff --git a/plugins/captcha/recaptcha/recaptchalib.php b/plugins/captcha/recaptcha/recaptchalib.php
new file mode 100644
index 0000000000000..dc0c526c15745
--- /dev/null
+++ b/plugins/captcha/recaptcha/recaptchalib.php
@@ -0,0 +1,146 @@
+" . self::$_signupUrl . "");
+ }
+ $this->_secret = $secret;
+ }
+
+ /**
+ * Encodes the given data into a query string format.
+ *
+ * @param array $data array of string elements to be encoded.
+ *
+ * @return string - encoded request.
+ */
+ private function _encodeQS($data)
+ {
+ $req = "";
+ foreach ($data as $key => $value)
+ {
+ $req .= $key . '=' . urlencode(stripslashes($value)) . '&';
+ }
+
+ // Cut the last '&'
+ $req = substr($req, 0, strlen($req) - 1);
+
+ return $req;
+ }
+
+ /**
+ * Submits an HTTP GET to a reCAPTCHA server.
+ *
+ * @param string $path url path to recaptcha server.
+ * @param array $data array of parameters to be sent.
+ *
+ * @return array response
+ */
+ private function _submitHTTPGet($path, $data)
+ {
+ $req = $this->_encodeQS($data);
+ $response = file_get_contents($path . $req);
+
+ return $response;
+ }
+
+ /**
+ * Calls the reCAPTCHA siteverify API to verify whether the user passes
+ * CAPTCHA test.
+ *
+ * @param string $remoteIp IP address of end user.
+ * @param string $response response string from recaptcha verification.
+ *
+ * @return ReCaptchaResponse
+ */
+ public function verifyResponse($remoteIp, $response)
+ {
+ // Discard empty solution submissions
+ if ($response == null || strlen($response) == 0)
+ {
+ $recaptchaResponse = new ReCaptchaResponse();
+ $recaptchaResponse->success = false;
+ $recaptchaResponse->errorCodes = 'missing-input';
+
+ return $recaptchaResponse;
+ }
+
+ $getResponse = $this->_submitHttpGet(
+ self::$_siteVerifyUrl,
+ array(
+ 'secret' => $this->_secret,
+ 'remoteip' => $remoteIp,
+ 'v' => self::$_version,
+ 'response' => $response
+ )
+ );
+ $answers = json_decode($getResponse, true);
+ $recaptchaResponse = new ReCaptchaResponse();
+
+ if (trim($answers['success']) == true)
+ {
+ $recaptchaResponse->success = true;
+ }
+ else
+ {
+ $recaptchaResponse->success = false;
+ $recaptchaResponse->errorCodes = isset($answers['error-codes']) ? $answers['error-codes'] : '';
+ }
+
+ return $recaptchaResponse;
+ }
+}