Skip to content

Commit

Permalink
MDL-48501 recaptchalib_v2: add new lib to support reCAPTCHA v2
Browse files Browse the repository at this point in the history
  • Loading branch information
jswebster committed Mar 8, 2018
1 parent 85ef1ad commit caae082
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 0 deletions.
1 change: 1 addition & 0 deletions lang/en/auth.php
Expand Up @@ -103,6 +103,7 @@
$string['getanaudiocaptcha'] = 'Get an audio CAPTCHA';
$string['getanimagecaptcha'] = 'Get an image CAPTCHA';
$string['getanothercaptcha'] = 'Get another CAPTCHA';
$string['getrecaptchaapi'] = 'To use reCAPTCHA you must get an API key from <a href=\'https://www.google.com/recaptcha/admin\'>https://www.google.com/recaptcha/admin</a>';
$string['guestloginbutton'] = 'Guest login button';
$string['changepassword'] = 'Change password URL';
$string['changepasswordhelp'] = 'URL of lost password recovery page, which will be sent to users in an email. Note that this setting will have no effect if a forgotten password URL is set in the authentication common settings.';
Expand Down
189 changes: 189 additions & 0 deletions lib/recaptchalib_v2.php
@@ -0,0 +1,189 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* This is a PHP library that handles calling reCAPTCHA v2.
*
* - Documentation
* {@link https://developers.google.com/recaptcha/docs/display}
* - Get a reCAPTCHA API Key
* {@link https://www.google.com/recaptcha/admin}
* - Discussion group
* {@link http://groups.google.com/group/recaptcha}
*
* @package core
* @copyright 2018 Jeff Webster
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

defined('MOODLE_INTERNAL') || die();

/**
* The reCAPTCHA URL's
*/
define('RECAPTCHA_API_URL', 'https://www.google.com/recaptcha/api.js');
define('RECAPTCHA_VERIFY_URL', 'https://www.google.com/recaptcha/api/siteverify');

/**
* Returns the language code the reCAPTCHA element should use.
* Google reCAPTCHA uses different language codes than Moodle so we must convert.
* https://developers.google.com/recaptcha/docs/language
*
* @return string A language code
*/
function recaptcha_lang() {

$mlang = current_language();

$glang = $mlang;
switch ($glang) {
case 'en':
$glang = 'en-GB';
break;
case 'en_us':
$glang = 'en';
break;
case 'zh_cn':
$glang = 'zh-CN';
break;
case 'zh_tw':
$glang = 'zh-TW';
break;
case 'fr_ca':
$glang = 'fr-CA';
break;
case 'pt_br':
$glang = 'pt-BR';
break;
case 'he':
$glang = 'iw';
break;
}
// For any language code that didn't change reduce down to the base language.
if (($mlang === $glang) and (strpos($mlang, '_') !== false)) {
list($glang, $trash) = explode('_', $mlang, 2);
}
return $glang;
}

/**
* Gets the challenge HTML
* This is called from the browser, and the resulting reCAPTCHA HTML widget
* is embedded within the HTML form it was called from.
*
* @param string $apiurl URL for reCAPTCHA API
* @param string $pubkey The public key for reCAPTCHA
* @return string - The HTML to be embedded in the user's form.
*/
function recaptcha_get_challenge_html($apiurl, $pubkey) {
global $CFG, $PAGE;

// To use reCAPTCHA you must have an API key.
if ($pubkey === null || $pubkey === '') {
return get_string('getrecaptchaapi', 'auth');
}

$jscode = "
var recaptchacallback = function() {
grecaptcha.render('recaptcha_element', {
'sitekey' : '$pubkey'
});
}";

$lang = recaptcha_lang();
$apicode = "\n<script type=\"text/javascript\" ";
$apicode .= "src=\"$apiurl?onload=recaptchacallback&render=explicit&hl=$lang\" async defer>";
$apicode .= "</script>\n";

$return = html_writer::script($jscode, '');
$return .= html_writer::div('', 'recaptcha_element', array('id' => 'recaptcha_element'));
$return .= $apicode;

return $return;
}

/**
* Calls an HTTP POST function to verify if the user's response was correct
*
* @param string $verifyurl URL for reCAPTCHA verification
* @param string $privkey The private key for reCAPTCHA
* @param string $remoteip The user's IP
* @param string $response The response from reCAPTCHA
* @return ReCaptchaResponse
*/
function recaptcha_check_response($verifyurl, $privkey, $remoteip, $response) {
global $CFG;
require_once($CFG->libdir.'/filelib.php');

// Check response - isvalid boolean, error string.
$checkresponse = array('isvalid' => false, 'error' => 'check-not-started');

// To use reCAPTCHA you must have an API key.
if ($privkey === null || $privkey === '') {
$checkresponse['isvalid'] = false;
$checkresponse['error'] = 'no-apikey';
return $checkresponse;
}

// For security reasons, you must pass the remote ip to reCAPTCHA.
if ($remoteip === null || $remoteip === '') {
$checkresponse['isvalid'] = false;
$checkresponse['error'] = 'no-remoteip';
return $checkresponse;
}

// Discard spam submissions.
if ($response === null || strlen($response) === 0) {
$checkresponse['isvalid'] = false;
$checkresponse['error'] = 'incorrect-captcha-sol';
return $checkresponse;
}

$params = array('secret' => $privkey, 'remoteip' => $remoteip, 'response' => $response);
$curl = new curl();
$curlresponse = $curl->post($verifyurl, $params);

if ($curl->get_errno() === 0) {
$curldata = json_decode($curlresponse);

if (isset($curldata->success) && $curldata->success === true) {
$checkresponse['isvalid'] = true;
$checkresponse['error'] = '';
} else {
$checkresponse['isvalid'] = false;
$checkresponse['error'] = $curldata->{error-codes};
}
} else {
$checkresponse['isvalid'] = false;
$checkresponse['error'] = 'check-failed';
}
return $checkresponse;
}

1 change: 1 addition & 0 deletions lib/upgrade.txt
Expand Up @@ -15,6 +15,7 @@ information provided here is intended especially for developers.
- notify()
* XMLDB now validates the PATH attribute on every install.xml file. Both the XMLDB editor and installation will fail
when a problem is detected with it. Please ensure your plugins contain correct directory relative paths.
* Add recaptchalib_v2.php for support of reCAPTCHA v2.

=== 3.4 ===

Expand Down

0 comments on commit caae082

Please sign in to comment.