PluginProbe
Google Authenticator / 0.46
Google Authenticator v0.46
trunk 0.20 0.30 0.35 0.36 0.37 0.38 0.39 0.40 0.41 0.42 0.43 0.44 0.45 0.46 0.47 0.48 0.50 0.51 0.52 0.53 0.54 0.55 0.56
google-authenticator / google-authenticator.php

google-authenticator.php in Google Authenticator 0.46, at google-authenticator.php

536 lines 20.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Google Authenticator
4 Plugin URI: http://henrik.schack.dk/google-authenticator-for-wordpress
5 Description: Two-Factor Authentication for WordPress using the Android/iPhone/Blackberry app as One Time Password generator.
6 Author: Henrik Schack
7 Version: 0.46
8 Author URI: http://henrik.schack.dk/
9 Compatibility: WordPress 3.8
10 Text Domain: google-authenticator
11 Domain Path: /lang
12
13 ----------------------------------------------------------------------------
14
15 Thanks to Bryan Ruiz for his Base32 encode/decode class, found at php.net.
16 Thanks to Tobias B�thge for his major code rewrite and German translation.
17 Thanks to Pascal de Bruijn for his relaxed mode idea.
18 Thanks to Daniel Werl for his usability tips.
19 Thanks to Dion Hulse for his bugfixes.
20 Thanks to Aldo Latino for his Italian translation.
21 Thanks to Kaijia Feng for his Simplified Chinese translation.
22 Thanks to Ian Dunn for fixing some depricated function calls.
23 Thanks to Kimmo Suominen for fixing the iPhone description issue.
24 Thanks to Alex Concha for some security tips.
25
26 ----------------------------------------------------------------------------
27
28 Copyright 2013 Henrik Schack (email : henrik@schack.dk)
29
30 This program is free software; you can redistribute it and/or modify
31 it under the terms of the GNU General Public License as published by
32 the Free Software Foundation; either version 2 of the License, or
33 (at your option) any later version.
34
35 This program is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 GNU General Public License for more details.
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
43 */
44
45 class GoogleAuthenticator {
46
47 static $instance; // to store a reference to the plugin, allows other plugins to remove actions
48
49 /**
50 * Constructor, entry point of the plugin
51 */
52 function __construct() {
53 self::$instance = $this;
54 add_action( 'init', array( $this, 'init' ) );
55 }
56
57 /**
58 * Initialization, Hooks, and localization
59 */
60 function init() {
61 require_once( 'base32.php' );
62
63 add_action( 'login_form', array( $this, 'loginform' ) );
64 add_action( 'login_footer', array( $this, 'loginfooter' ) );
65 add_filter( 'authenticate', array( $this, 'check_otp' ), 50, 3 );
66
67 if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
68 add_action( 'wp_ajax_GoogleAuthenticator_action', array( $this, 'ajax_callback' ) );
69
70 add_action( 'personal_options_update', array( $this, 'personal_options_update' ) );
71 add_action( 'profile_personal_options', array( $this, 'profile_personal_options' ) );
72 add_action( 'edit_user_profile', array( $this, 'edit_user_profile' ) );
73 add_action( 'edit_user_profile_update', array( $this, 'edit_user_profile_update' ) );
74
75 load_plugin_textdomain( 'google-authenticator', false, basename( dirname( __FILE__ ) ) . '/lang' );
76 }
77
78 /**
79 * Check the verification code entered by the user.
80 */
81 function verify( $secretkey, $thistry, $relaxedmode, $lasttimeslot ) {
82
83 // Did the user enter 6 digits ?
84 if ( strlen( $thistry ) != 6) {
85 return false;
86 } else {
87 $thistry = intval ( $thistry );
88 }
89
90 // If user is running in relaxed mode, we allow more time drifting
91 // �4 min, as opposed to � 30 seconds in normal mode.
92 if ( $relaxedmode == 'enabled' ) {
93 $firstcount = -8;
94 $lastcount = 8;
95 } else {
96 $firstcount = -1;
97 $lastcount = 1;
98 }
99
100 $tm = floor( time() / 30 );
101
102 $secretkey=Base32::decode($secretkey);
103 // Keys from 30 seconds before and after are valid aswell.
104 for ($i=$firstcount; $i<=$lastcount; $i++) {
105 // Pack time into binary string
106 $time=chr(0).chr(0).chr(0).chr(0).pack('N*',$tm+$i);
107 // Hash it with users secret key
108 $hm = hash_hmac( 'SHA1', $time, $secretkey, true );
109 // Use last nipple of result as index/offset
110 $offset = ord(substr($hm,-1)) & 0x0F;
111 // grab 4 bytes of the result
112 $hashpart=substr($hm,$offset,4);
113 // Unpak binary value
114 $value=unpack("N",$hashpart);
115 $value=$value[1];
116 // Only 32 bits
117 $value = $value & 0x7FFFFFFF;
118 $value = $value % 1000000;
119 if ( $value === $thistry ) {
120 // Check for replay (Man-in-the-middle) attack.
121 // Since this is not Star Trek, time can only move forward,
122 // meaning current login attempt has to be in the future compared to
123 // last successful login.
124 if ( $lasttimeslot >= ($tm+$i) ) {
125 return false;
126 }
127 // Return timeslot in which login happened.
128 return $tm+$i;
129 }
130 }
131 return false;
132 }
133
134 /**
135 * Create a new random secret for the Google Authenticator app.
136 * 16 characters, randomly chosen from the allowed Base32 characters
137 * equals 10 bytes = 80 bits, as 256^10 = 32^16 = 2^80
138 */
139 function create_secret() {
140 $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; // allowed characters in Base32
141 $secret = '';
142 for ( $i = 0; $i < 16; $i++ ) {
143 $secret .= substr( $chars, wp_rand( 0, strlen( $chars ) - 1 ), 1 );
144 }
145 return $secret;
146 }
147
148
149 /**
150 * Add verification code field to login form.
151 */
152 function loginform() {
153 echo "\t<p>\n";
154 echo "\t\t<label title=\"".__('If you don\'t have Google Authenticator enabled for your WordPress account, leave this field empty.','google-authenticator')."\">".__('Google Authenticator code','google-authenticator')."<span id=\"google-auth-info\"></span><br />\n";
155 echo "\t\t<input type=\"text\" name=\"googleotp\" id=\"user_email\" class=\"input\" value=\"\" size=\"20\" style=\"ime-mode: inactive;\" /></label>\n";
156 echo "\t</p>\n";
157 }
158
159 /**
160 * Disable autocomplete on Google Authenticator code input field.
161 */
162 function loginfooter() {
163 echo "\n<script type=\"text/javascript\">\n";
164 echo "\ttry{\n";
165 echo "\t\tdocument.getElementById('user_email').setAttribute('autocomplete','off');\n";
166 echo "\t} catch(e){}\n";
167 echo "</script>\n";
168 }
169
170 /**
171 * Login form handling.
172 * Check Google Authenticator verification code, if user has been setup to do so.
173 * @param wordpressuser
174 * @return user/loginstatus
175 */
176 function check_otp( $user, $username = '', $password = '' ) {
177 // Store result of loginprocess, so far.
178 $userstate = $user;
179
180 // Get information on user, we need this in case an app password has been enabled,
181 // since the $user var only contain an error at this point in the login flow.
182 $user = get_user_by( 'login', $username );
183
184 // Does the user have the Google Authenticator enabled ?
185 if ( isset( $user->ID ) && trim(get_user_option( 'googleauthenticator_enabled', $user->ID ) ) == 'enabled' ) {
186
187 // Get the users secret
188 $GA_secret = trim( get_user_option( 'googleauthenticator_secret', $user->ID ) );
189
190 // Figure out if user is using relaxed mode ?
191 $GA_relaxedmode = trim( get_user_option( 'googleauthenticator_relaxedmode', $user->ID ) );
192
193 // Get the verification code entered by the user trying to login
194 if ( !empty( $_POST['googleotp'] )) { // Prevent PHP notices when using app password login
195 $otp = trim( $_POST[ 'googleotp' ] );
196 } else {
197 $otp = '';
198 }
199 // When was the last successful login performed ?
200 $lasttimeslot = trim( get_user_option( 'googleauthenticator_lasttimeslot', $user->ID ) );
201 // Valid code ?
202 if ( $timeslot = $this->verify( $GA_secret, $otp, $GA_relaxedmode, $lasttimeslot ) ) {
203 // Store the timeslot in which login was successful.
204 update_user_option( $user->ID, 'googleauthenticator_lasttimeslot', $timeslot, true );
205 return $userstate;
206 } else {
207 // No, lets see if an app password is enabled, and this is an XMLRPC / APP login ?
208 if ( trim( get_user_option( 'googleauthenticator_pwdenabled', $user->ID ) ) == 'enabled' && ( defined('XMLRPC_REQUEST') || defined('APP_REQUEST') ) ) {
209 $GA_passwords = json_decode( get_user_option( 'googleauthenticator_passwords', $user->ID ) );
210 $passwordhash = trim($GA_passwords->{'password'} );
211 $usersha1 = sha1( strtoupper( str_replace( ' ', '', $password ) ) );
212 if ( $passwordhash == $usersha1 ) { // ToDo: Remove after some time when users have migrated to new format
213 return new WP_User( $user->ID );
214 // Try the new version based on thee wp_hash_password function
215 } elseif (wp_check_password( strtoupper( str_replace( ' ', '', $password ) ), $passwordhash)) {
216 return new WP_User( $user->ID );
217 } else {
218 // Wrong XMLRPC/APP password !
219 return new WP_Error( 'invalid_google_authenticator_password', __( '<strong>ERROR</strong>: The Google Authenticator password is incorrect.', 'google-authenticator' ) );
220 }
221 } else {
222 return new WP_Error( 'invalid_google_authenticator_token', __( '<strong>ERROR</strong>: The Google Authenticator code is incorrect or has expired.', 'google-authenticator' ) );
223 }
224 }
225 }
226 // Google Authenticator isn't enabled for this account,
227 // just resume normal authentication.
228 return $userstate;
229 }
230
231
232 /**
233 * Extend personal profile page with Google Authenticator settings.
234 */
235 function profile_personal_options() {
236 global $user_id, $is_profile_page;
237
238 // If editing of Google Authenticator settings has been disabled, just return
239 $GA_hidefromuser = trim( get_user_option( 'googleauthenticator_hidefromuser', $user_id ) );
240 if ( $GA_hidefromuser == 'enabled') return;
241
242 $GA_secret = trim( get_user_option( 'googleauthenticator_secret', $user_id ) );
243 $GA_enabled = trim( get_user_option( 'googleauthenticator_enabled', $user_id ) );
244 $GA_relaxedmode = trim( get_user_option( 'googleauthenticator_relaxedmode', $user_id ) );
245 $GA_description = trim( get_user_option( 'googleauthenticator_description', $user_id ) );
246 $GA_pwdenabled = trim( get_user_option( 'googleauthenticator_pwdenabled', $user_id ) );
247 $GA_password = trim( get_user_option( 'googleauthenticator_passwords', $user_id ) );
248
249 // We dont store the generated app password in cleartext so there is no point in trying
250 // to show the user anything except from the fact that a password exists.
251 if ( $GA_password != '' ) {
252 $GA_password = "XXXX XXXX XXXX XXXX";
253 }
254
255 // In case the user has no secret ready (new install), we create one.
256 if ( '' == $GA_secret ) {
257 $GA_secret = $this->create_secret();
258 }
259
260 // Use "WordPress Blog" as default description
261 if ( '' == $GA_description ) {
262 $GA_description = __( 'WordPressBlog', 'google-authenticator' );
263 }
264
265 echo "<h3>".__( 'Google Authenticator Settings', 'google-authenticator' )."</h3>\n";
266
267 echo "<table class=\"form-table\">\n";
268 echo "<tbody>\n";
269 echo "<tr>\n";
270 echo "<th scope=\"row\">".__( 'Active', 'google-authenticator' )."</th>\n";
271 echo "<td>\n";
272 echo "<input name=\"GA_enabled\" id=\"GA_enabled\" class=\"tog\" type=\"checkbox\"" . checked( $GA_enabled, 'enabled', false ) . "/>\n";
273 echo "</td>\n";
274 echo "</tr>\n";
275
276 if ( $is_profile_page || IS_PROFILE_PAGE ) {
277 echo "<tr>\n";
278 echo "<th scope=\"row\">".__( 'Relaxed mode', 'google-authenticator' )."</th>\n";
279 echo "<td>\n";
280 echo "<input name=\"GA_relaxedmode\" id=\"GA_relaxedmode\" class=\"tog\" type=\"checkbox\"" . checked( $GA_relaxedmode, 'enabled', false ) . "/><span class=\"description\">".__(' Relaxed mode allows for more time drifting on your phone clock (&#177;4 min).','google-authenticator')."</span>\n";
281 echo "</td>\n";
282 echo "</tr>\n";
283
284 echo "<tr>\n";
285 echo "<th><label for=\"GA_description\">".__('Description','google-authenticator')."</label></th>\n";
286 echo "<td><input name=\"GA_description\" id=\"GA_description\" value=\"{$GA_description}\" type=\"text\" size=\"25\" /><span class=\"description\">".__(' Description that you\'ll see in the Google Authenticator app on your phone.','google-authenticator')."</span><br /></td>\n";
287 echo "</tr>\n";
288
289 echo "<tr>\n";
290 echo "<th><label for=\"GA_secret\">".__('Secret','google-authenticator')."</label></th>\n";
291 echo "<td>\n";
292 echo "<input name=\"GA_secret\" id=\"GA_secret\" value=\"{$GA_secret}\" readonly=\"readonly\" type=\"text\" size=\"25\" />";
293 echo "<input name=\"GA_newsecret\" id=\"GA_newsecret\" value=\"".__("Create new secret",'google-authenticator')."\" type=\"button\" class=\"button\" />";
294 echo "<input name=\"show_qr\" id=\"show_qr\" value=\"".__("Show/Hide QR code",'google-authenticator')."\" type=\"button\" class=\"button\" onclick=\"ShowQRCodeAfterWarning();\" />";
295 echo "</td>\n";
296 echo "</tr>\n";
297
298 echo "<tr>\n";
299 echo "<th></th>\n";
300 echo "<td><div id=\"GA_QR_INFO\" style=\"display: none\" >";
301 echo "<img id=\"GA_QRCODE\" src=\"\" alt=\"QR Code\"/>";
302
303 echo '<span class="description"><br/> ' . __( 'Scan this with the Google Authenticator app.', 'google-authenticator' ) . '</span>';
304 echo "</div></td>\n";
305 echo "</tr>\n";
306
307 echo "<tr>\n";
308 echo "<th scope=\"row\">".__( 'Enable App password', 'google-authenticator' )."</th>\n";
309 echo "<td>\n";
310 echo "<input name=\"GA_pwdenabled\" id=\"GA_pwdenabled\" class=\"tog\" type=\"checkbox\"" . checked( $GA_pwdenabled, 'enabled', false ) . "/><span class=\"description\">".__(' Enabling an App password will decrease your overall login security.','google-authenticator')."</span>\n";
311 echo "</td>\n";
312 echo "</tr>\n";
313
314 echo "<tr>\n";
315 echo "<th></th>\n";
316 echo "<td>\n";
317 echo "<input name=\"GA_password\" id=\"GA_password\" readonly=\"readonly\" value=\"".$GA_password."\" type=\"text\" size=\"25\" />";
318 echo "<input name=\"GA_createpassword\" id=\"GA_createpassword\" value=\"".__("Create new password",'google-authenticator')."\" type=\"button\" class=\"button\" />";
319 echo "<span class=\"description\" id=\"GA_passworddesc\">".__(' Password is not stored in cleartext, this is your only chance to see it.','google-authenticator')."</span>\n";
320 echo "</td>\n";
321 echo "</tr>\n";
322 }
323
324
325 echo "</tbody></table>\n";
326 echo "<script type=\"text/javascript\">\n";
327 echo "var GAnonce='".wp_create_nonce('GoogleAuthenticatoraction')."';\n";
328
329 echo "var qrcodewarningtext = '";
330 echo __( "WARNING:\\n\\nShowing the QR code will use the Google Chart API to do so.\\nIf you do not trust Google, please press Cancel and enter the code manually.",'google-authenticator' );
331 echo "';\n";
332
333 echo <<<ENDOFJS
334 var pwdata;
335 jQuery('#GA_newsecret').bind('click', function() {
336 var data=new Object();
337 data['action'] = 'GoogleAuthenticator_action';
338 data['nonce'] = GAnonce;
339 jQuery.post(ajaxurl, data, function(response) {
340 jQuery('#GA_secret').val(response['new-secret']);
341 chl=escape("otpauth://totp/"+jQuery('#GA_description').val()+"?secret="+jQuery('#GA_secret').val());
342 qrcodeurl="https://chart.googleapis.com/chart?cht=qr&chs=300x300&chld=H|0&chl="+chl;
343 jQuery('#GA_QRCODE').attr('src',qrcodeurl);
344 jQuery('#GA_QR_INFO').show('slow');
345 });
346 });
347
348 jQuery('#GA_description').bind('focus blur change keyup', function() {
349 // Only update QRCode if it's already visible
350 if (jQuery('#GA_QR_INFO').is(':visible')) {
351 chl=escape("otpauth://totp/"+jQuery('#GA_description').val()+"?secret="+jQuery('#GA_secret').val());
352 qrcodeurl="https://chart.googleapis.com/chart?cht=qr&chs=300x300&chld=H|0&chl="+chl;
353 jQuery('#GA_QRCODE').attr('src',qrcodeurl);
354 }
355 });
356
357 jQuery('#GA_createpassword').bind('click',function() {
358 var data=new Object();
359 data['action'] = 'GoogleAuthenticator_action';
360 data['nonce'] = GAnonce;
361 data['save'] = 1;
362 jQuery.post(ajaxurl, data, function(response) {
363 jQuery('#GA_password').val(response['new-secret'].match(new RegExp(".{0,4}","g")).join(' '));
364 jQuery('#GA_passworddesc').show();
365 });
366 });
367
368 jQuery('#GA_enabled').bind('change',function() {
369 GoogleAuthenticator_apppasswordcontrol();
370 });
371
372 jQuery(document).ready(function() {
373 jQuery('#GA_passworddesc').hide();
374 GoogleAuthenticator_apppasswordcontrol();
375 });
376
377 function GoogleAuthenticator_apppasswordcontrol() {
378 if (jQuery('#GA_enabled').is(':checked')) {
379 jQuery('#GA_pwdenabled').removeAttr('disabled');
380 jQuery('#GA_createpassword').removeAttr('disabled');
381 } else {
382 jQuery('#GA_pwdenabled').removeAttr('checked')
383 jQuery('#GA_pwdenabled').attr('disabled', true);
384 jQuery('#GA_createpassword').attr('disabled', true);
385 }
386 }
387
388 function ShowQRCodeAfterWarning() {
389 if (jQuery('#GA_QR_INFO').is(':hidden')) {
390 if ( confirm(qrcodewarningtext) ) {
391 chl=escape("otpauth://totp/"+jQuery('#GA_description').val()+"?secret="+jQuery('#GA_secret').val());
392 qrcodeurl="https://chart.googleapis.com/chart?cht=qr&chs=300x300&chld=H|0&chl="+chl;
393 jQuery('#GA_QRCODE').attr('src',qrcodeurl);
394 jQuery('#GA_QR_INFO').show('slow');
395 }
396 } else {
397 jQuery('#GA_QR_INFO').hide('slow');
398 }
399 }
400 </script>
401 ENDOFJS;
402 }
403
404 /**
405 * Form handling of Google Authenticator options added to personal profile page (user editing his own profile)
406 */
407 function personal_options_update() {
408 global $user_id;
409
410 // If editing of Google Authenticator settings has been disabled, just return
411 $GA_hidefromuser = trim( get_user_option( 'googleauthenticator_hidefromuser', $user_id ) );
412 if ( $GA_hidefromuser == 'enabled') return;
413
414
415 $GA_enabled = ! empty( $_POST['GA_enabled'] );
416 $GA_description = trim( sanitize_text_field($_POST['GA_description'] ) );
417 $GA_relaxedmode = ! empty( $_POST['GA_relaxedmode'] );
418 $GA_secret = trim( $_POST['GA_secret'] );
419 $GA_pwdenabled = ! empty( $_POST['GA_pwdenabled'] );
420 $GA_password = str_replace(' ', '', trim( $_POST['GA_password'] ) );
421
422 if ( ! $GA_enabled ) {
423 $GA_enabled = 'disabled';
424 } else {
425 $GA_enabled = 'enabled';
426 }
427
428 if ( ! $GA_relaxedmode ) {
429 $GA_relaxedmode = 'disabled';
430 } else {
431 $GA_relaxedmode = 'enabled';
432 }
433
434
435 if ( ! $GA_pwdenabled ) {
436 $GA_pwdenabled = 'disabled';
437 } else {
438 $GA_pwdenabled = 'enabled';
439 }
440
441 // Only store password if a new one has been generated.
442 if (strtoupper($GA_password) != 'XXXXXXXXXXXXXXXX' ) {
443 // Store the password in a format that can be expanded easily later on if needed.
444 $GA_password = array( 'appname' => 'Default', 'password' => wp_hash_password( $GA_password ) );
445 update_user_option( $user_id, 'googleauthenticator_passwords', json_encode( $GA_password ), true );
446 }
447
448 update_user_option( $user_id, 'googleauthenticator_enabled', $GA_enabled, true );
449 update_user_option( $user_id, 'googleauthenticator_description', $GA_description, true );
450 update_user_option( $user_id, 'googleauthenticator_relaxedmode', $GA_relaxedmode, true );
451 update_user_option( $user_id, 'googleauthenticator_secret', $GA_secret, true );
452 update_user_option( $user_id, 'googleauthenticator_pwdenabled', $GA_pwdenabled, true );
453
454 }
455
456 /**
457 * Extend profile page with ability to enable/disable Google Authenticator authentication requirement.
458 * Used by an administrator when editing other users.
459 */
460 function edit_user_profile() {
461 global $user_id;
462 $GA_enabled = trim( get_user_option( 'googleauthenticator_enabled', $user_id ) );
463 $GA_hidefromuser = trim( get_user_option( 'googleauthenticator_hidefromuser', $user_id ) );
464 echo "<h3>".__('Google Authenticator Settings','google-authenticator')."</h3>\n";
465 echo "<table class=\"form-table\">\n";
466 echo "<tbody>\n";
467
468 echo "<tr>\n";
469 echo "<th scope=\"row\">".__('Hide settings from user','google-authenticator')."</th>\n";
470 echo "<td>\n";
471 echo "<div><input name=\"GA_hidefromuser\" id=\"GA_hidefromuser\" class=\"tog\" type=\"checkbox\"" . checked( $GA_hidefromuser, 'enabled', false ) . "/>\n";
472 echo "</td>\n";
473 echo "</tr>\n";
474
475 echo "<tr>\n";
476 echo "<th scope=\"row\">".__('Active','google-authenticator')."</th>\n";
477 echo "<td>\n";
478 echo "<div><input name=\"GA_enabled\" id=\"GA_enabled\" class=\"tog\" type=\"checkbox\"" . checked( $GA_enabled, 'enabled', false ) . "/>\n";
479 echo "</td>\n";
480 echo "</tr>\n";
481
482 echo "</tbody>\n";
483 echo "</table>\n";
484 }
485
486 /**
487 * Form handling of Google Authenticator options on edit profile page (admin user editing other user)
488 */
489 function edit_user_profile_update() {
490 global $user_id;
491
492 $GA_enabled = ! empty( $_POST['GA_enabled'] );
493 $GA_hidefromuser = ! empty( $_POST['GA_hidefromuser'] );
494
495 if ( ! $GA_enabled ) {
496 $GA_enabled = 'disabled';
497 } else {
498 $GA_enabled = 'enabled';
499 }
500
501 if ( ! $GA_hidefromuser ) {
502 $GA_hidefromuser = 'disabled';
503 } else {
504 $GA_hidefromuser = 'enabled';
505 }
506
507 update_user_option( $user_id, 'googleauthenticator_enabled', $GA_enabled, true );
508 update_user_option( $user_id, 'googleauthenticator_hidefromuser', $GA_hidefromuser, true );
509
510 }
511
512
513 /**
514 * AJAX callback function used to generate new secret
515 */
516 function ajax_callback() {
517 global $user_id;
518
519 // Some AJAX security
520 check_ajax_referer( 'GoogleAuthenticatoraction', 'nonce' );
521
522 // Create new secret, using the users password hash as input for further hashing
523 $secret = $this->create_secret();
524
525 $result = array( 'new-secret' => $secret );
526 header( 'Content-Type: application/json' );
527 echo json_encode( $result );
528
529 // die() is required to return a proper result
530 die();
531 }
532
533 } // end class
534
535 $google_authenticator = new GoogleAuthenticator;
536 ?>