Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 // This file is part of Moodle - http://moodle.org/
17
//
18
// Moodle is free software: you can redistribute it and/or modify
19
// it under the terms of the GNU General Public License as published by
20
// the Free Software Foundation, either version 3 of the License, or
21
// (at your option) any later version.
22
//
23
// Moodle is distributed in the hope that it will be useful,
24
// but WITHOUT ANY WARRANTY; without even the implied warranty of
25
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
// GNU General Public License for more details.
27
//
28
// You should have received a copy of the GNU General Public License
29
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
30
 
31
/**
32
 * This is a PHP library that handles calling reCAPTCHA v2.
33
 *
34
 *    - Documentation
35
 *          {@link https://developers.google.com/recaptcha/docs/display}
36
 *    - Get a reCAPTCHA API Key
37
 *          {@link https://www.google.com/recaptcha/admin}
38
 *    - Discussion group
39
 *          {@link http://groups.google.com/group/recaptcha}
40
 *
41
 * @package core
42
 * @copyright 2018 Jeff Webster
43
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44
 */
45
 
46
defined('MOODLE_INTERNAL') || die();
47
 
48
/**
49
 * The reCAPTCHA URL's
50
 */
51
define('RECAPTCHA_API_URL', 'https://www.recaptcha.net/recaptcha/api.js');
52
define('RECAPTCHA_VERIFY_URL', 'https://www.recaptcha.net/recaptcha/api/siteverify');
53
 
54
/**
55
 * Returns the language code the reCAPTCHA element should use.
56
 * Google reCAPTCHA uses different language codes than Moodle so we must convert.
57
 * https://developers.google.com/recaptcha/docs/language
58
 *
59
 * @param string $lang Language to use. If not provided, get current language.
60
 * @return string A language code
61
 */
62
function recaptcha_lang($lang = null) {
63
 
64
    if (empty($lang)) {
65
        $lang = current_language();
66
    }
67
 
68
    $glang = $lang;
69
    switch ($glang) {
70
        case 'en':
71
            $glang = 'en-GB';
72
            break;
73
        case 'en_us':
74
            $glang = 'en';
75
            break;
76
        case 'zh_cn':
77
            $glang = 'zh-CN';
78
            break;
79
        case 'zh_tw':
80
            $glang = 'zh-TW';
81
            break;
82
        case 'fr_ca':
83
            $glang = 'fr-CA';
84
            break;
85
        case 'pt_br':
86
            $glang = 'pt-BR';
87
            break;
88
        case 'he':
89
            $glang = 'iw';
90
            break;
91
    }
92
    // For any language code that didn't change reduce down to the base language.
93
    if (($lang === $glang) and (strpos($lang, '_') !== false)) {
94
        list($glang, $trash) = explode('_', $lang, 2);
95
    }
96
    return $glang;
97
}
98
 
99
/**
100
 * Gets the challenge HTML
101
 * This is called from the browser, and the resulting reCAPTCHA HTML widget
102
 * is embedded within the HTML form it was called from.
103
 *
104
 * @param string $apiurl URL for reCAPTCHA API
105
 * @param string $pubkey The public key for reCAPTCHA
106
 * @param string $lang Language to use. If not provided, get current language.
107
 * @param bool $compactmode If true, use the compact widget.
108
 * @return string - The HTML to be embedded in the user's form.
109
 */
110
function recaptcha_get_challenge_html($apiurl, $pubkey, $lang = null, bool $compactmode = false) {
111
    global $CFG, $PAGE;
112
 
113
    // To use reCAPTCHA you must have an API key.
114
    if ($pubkey === null || $pubkey === '') {
115
        return get_string('getrecaptchaapi', 'auth');
116
    }
117
 
118
    $jscode = "
119
        var recaptchacallback = function() {
120
            grecaptcha.render('recaptcha_element', {
121
              'sitekey' : '$pubkey'
122
            });
123
        }";
124
 
125
    $lang = recaptcha_lang($lang);
126
    $apicode = "\n<script type=\"text/javascript\" ";
127
    $apicode .= "src=\"$apiurl?onload=recaptchacallback&render=explicit&hl=$lang\" async defer>";
128
    $apicode .= "</script>\n";
129
 
130
    $return = html_writer::script($jscode, '');
131
    $return .= html_writer::div('', 'recaptcha_element', [
132
        'id' => 'recaptcha_element',
133
        'data-size' => ($compactmode ? 'compact' : 'normal'),
134
    ]);
135
    $return .= $apicode;
136
 
137
    return $return;
138
}
139
 
140
/**
141
 * Calls an HTTP POST function to verify if the user's response was correct
142
 *
143
 * @param string $verifyurl URL for reCAPTCHA verification
144
 * @param string $privkey The private key for reCAPTCHA
145
 * @param string $remoteip The user's IP
146
 * @param string $response The response from reCAPTCHA
147
 * @return array
148
 */
149
function recaptcha_check_response($verifyurl, $privkey, $remoteip, $response) {
150
    global $CFG;
151
    require_once($CFG->libdir.'/filelib.php');
152
 
153
    // Check response - isvalid boolean, error string.
154
    $checkresponse = array('isvalid' => false, 'error' => 'check-not-started');
155
 
156
    // To use reCAPTCHA you must have an API key.
157
    if ($privkey === null || $privkey === '') {
158
        $checkresponse['isvalid'] = false;
159
        $checkresponse['error'] = 'no-apikey';
160
        return $checkresponse;
161
    }
162
 
163
    // For security reasons, you must pass the remote ip to reCAPTCHA.
164
    if ($remoteip === null || $remoteip === '') {
165
        $checkresponse['isvalid'] = false;
166
        $checkresponse['error'] = 'no-remoteip';
167
        return $checkresponse;
168
    }
169
 
170
    // Discard spam submissions.
171
    if ($response === null || strlen($response) === 0) {
172
        $checkresponse['isvalid'] = false;
173
        $checkresponse['error'] = 'incorrect-captcha-sol';
174
        return $checkresponse;
175
    }
176
 
177
    $params = array('secret' => $privkey, 'remoteip' => $remoteip, 'response' => $response);
178
    $curl = new curl();
179
    $curlresponse = $curl->post($verifyurl, $params);
180
 
181
    if ($curl->get_errno() === 0) {
182
        $curldata = json_decode($curlresponse);
183
 
184
        if (isset($curldata->success) && $curldata->success === true) {
185
            $checkresponse['isvalid'] = true;
186
            $checkresponse['error'] = '';
187
        } else {
188
            $checkresponse['isvalid'] = false;
189
            $checkresponse['error'] = $curldata->{'error-codes'};
190
        }
191
    } else {
192
        $checkresponse['isvalid'] = false;
193
        $checkresponse['error'] = 'check-failed';
194
    }
195
    return $checkresponse;
196
}
197