Google Authenticator - Version 0.46

Version Description

  • Man-in-the-middle attack protection added.
  • Show warning before displaying the QR code.
  • FAQ updated.
Download this release

Release Info

Developer Henrik.Schack
Plugin Icon wp plugin Google Authenticator
Version 0.46
Comparing to
See all releases

Code changes from version 0.45 to 0.46

Files changed (2) hide show
  1. google-authenticator.php +48 -19
  2. readme.txt +6 -5
google-authenticator.php CHANGED
@@ -4,7 +4,7 @@ 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.45
8
  Author URI: http://henrik.schack.dk/
9
  Compatibility: WordPress 3.8
10
  Text Domain: google-authenticator
@@ -78,7 +78,7 @@ function init() {
78
  /**
79
  * Check the verification code entered by the user.
80
  */
81
- function verify( $secretkey, $thistry, $relaxedmode ) {
82
 
83
  // Did the user enter 6 digits ?
84
  if ( strlen( $thistry ) != 6) {
@@ -117,7 +117,15 @@ function verify( $secretkey, $thistry, $relaxedmode ) {
117
  $value = $value & 0x7FFFFFFF;
118
  $value = $value % 1000000;
119
  if ( $value === $thistry ) {
120
- return true;
 
 
 
 
 
 
 
 
121
  }
122
  }
123
  return false;
@@ -188,8 +196,12 @@ function check_otp( $user, $username = '', $password = '' ) {
188
  } else {
189
  $otp = '';
190
  }
 
 
191
  // Valid code ?
192
- if ( $this->verify( $GA_secret, $otp, $GA_relaxedmode ) ) {
 
 
193
  return $userstate;
194
  } else {
195
  // No, lets see if an app password is enabled, and this is an XMLRPC / APP login ?
@@ -210,7 +222,7 @@ function check_otp( $user, $username = '', $password = '' ) {
210
  return new WP_Error( 'invalid_google_authenticator_token', __( '<strong>ERROR</strong>: The Google Authenticator code is incorrect or has expired.', 'google-authenticator' ) );
211
  }
212
  }
213
- }
214
  // Google Authenticator isn't enabled for this account,
215
  // just resume normal authentication.
216
  return $userstate;
@@ -261,10 +273,6 @@ function profile_personal_options() {
261
  echo "</td>\n";
262
  echo "</tr>\n";
263
 
264
- // Create URL for the Google charts QR code generator.
265
- $chl = rawurlencode( 'otpauth://totp/'.rawurlencode( $GA_description ).'?secret='.rawurlencode( $GA_secret ) );
266
- $qrcodeurl = "https://chart.googleapis.com/chart?cht=qr&amp;chs=300x300&amp;chld=H|0&amp;chl={$chl}";
267
-
268
  if ( $is_profile_page || IS_PROFILE_PAGE ) {
269
  echo "<tr>\n";
270
  echo "<th scope=\"row\">".__( 'Relaxed mode', 'google-authenticator' )."</th>\n";
@@ -283,14 +291,15 @@ function profile_personal_options() {
283
  echo "<td>\n";
284
  echo "<input name=\"GA_secret\" id=\"GA_secret\" value=\"{$GA_secret}\" readonly=\"readonly\" type=\"text\" size=\"25\" />";
285
  echo "<input name=\"GA_newsecret\" id=\"GA_newsecret\" value=\"".__("Create new secret",'google-authenticator')."\" type=\"button\" class=\"button\" />";
286
- echo "<input name=\"show_qr\" id=\"show_qr\" value=\"".__("Show/Hide QR code",'google-authenticator')."\" type=\"button\" class=\"button\" onclick=\"jQuery('#GA_QR_INFO').toggle('slow');\" />";
287
  echo "</td>\n";
288
  echo "</tr>\n";
289
 
290
  echo "<tr>\n";
291
  echo "<th></th>\n";
292
  echo "<td><div id=\"GA_QR_INFO\" style=\"display: none\" >";
293
- echo "<img id=\"GA_QRCODE\" src=\"{$qrcodeurl}\" alt=\"QR Code\"/>";
 
294
  echo '<span class="description"><br/> ' . __( 'Scan this with the Google Authenticator app.', 'google-authenticator' ) . '</span>';
295
  echo "</div></td>\n";
296
  echo "</tr>\n";
@@ -316,6 +325,11 @@ function profile_personal_options() {
316
  echo "</tbody></table>\n";
317
  echo "<script type=\"text/javascript\">\n";
318
  echo "var GAnonce='".wp_create_nonce('GoogleAuthenticatoraction')."';\n";
 
 
 
 
 
319
  echo <<<ENDOFJS
320
  var pwdata;
321
  jQuery('#GA_newsecret').bind('click', function() {
@@ -329,14 +343,17 @@ function profile_personal_options() {
329
  jQuery('#GA_QRCODE').attr('src',qrcodeurl);
330
  jQuery('#GA_QR_INFO').show('slow');
331
  });
332
- });
333
-
334
  jQuery('#GA_description').bind('focus blur change keyup', function() {
335
- chl=escape("otpauth://totp/"+jQuery('#GA_description').val()+"?secret="+jQuery('#GA_secret').val());
336
- qrcodeurl="https://chart.googleapis.com/chart?cht=qr&chs=300x300&chld=H|0&chl="+chl;
337
- jQuery('#GA_QRCODE').attr('src',qrcodeurl);
 
 
 
338
  });
339
-
340
  jQuery('#GA_createpassword').bind('click',function() {
341
  var data=new Object();
342
  data['action'] = 'GoogleAuthenticator_action';
@@ -366,10 +383,22 @@ function profile_personal_options() {
366
  jQuery('#GA_pwdenabled').attr('disabled', true);
367
  jQuery('#GA_createpassword').attr('disabled', true);
368
  }
369
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
370
  </script>
371
  ENDOFJS;
372
-
373
  }
374
 
375
  /**
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
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) {
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;
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 ?
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;
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";
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";
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() {
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';
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
  /**
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate Link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=henri
4
  Tags: authentication,otp,password,security,login,android,iphone,blackberry
5
  Requires at least: 3.8
6
  Tested up to: 3.8
7
- Stable tag: 0.45
8
 
9
  Google Authenticator for your WordPress blog.
10
 
@@ -30,10 +30,6 @@ You may also want to write down the secret on a piece of paper and store it in a
30
 
31
  == Frequently Asked Questions ==
32
 
33
- = The iPhone app keeps telling me I'm trying to scan an authentication token barcode that isn't valid, what to do ? =
34
-
35
- Apparently the iPhone app won't accept a barcode containing space characters in the description, removing space characters in the description should fix the problem.
36
-
37
  = Can I use Google Authenticator for WordPress with the Android/iPhone apps for WordPress? =
38
 
39
  Yes, you can enable the App password feature to make that possible, but notice that the XMLRPC interface isn't protected by two-factor authentication, only a long password.
@@ -72,6 +68,11 @@ Yes, there is a webbased version here : http://gauth.apps.gbraad.nl/ Github proj
72
 
73
  == Changelog ==
74
 
 
 
 
 
 
75
  = 0.45 =
76
  * Spaces in the description field should now work on iPhones.
77
  * Some depricated function calls replaced.
4
  Tags: authentication,otp,password,security,login,android,iphone,blackberry
5
  Requires at least: 3.8
6
  Tested up to: 3.8
7
+ Stable tag: 0.46
8
 
9
  Google Authenticator for your WordPress blog.
10
 
30
 
31
  == Frequently Asked Questions ==
32
 
 
 
 
 
33
  = Can I use Google Authenticator for WordPress with the Android/iPhone apps for WordPress? =
34
 
35
  Yes, you can enable the App password feature to make that possible, but notice that the XMLRPC interface isn't protected by two-factor authentication, only a long password.
68
 
69
  == Changelog ==
70
 
71
+ = 0.46 =
72
+ * Man-in-the-middle attack protection added.
73
+ * Show warning before displaying the QR code.
74
+ * FAQ updated.
75
+
76
  = 0.45 =
77
  * Spaces in the description field should now work on iPhones.
78
  * Some depricated function calls replaced.