summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2018-07-11 14:19:36 -0400
committerAnthony G. Basile <blueness@gentoo.org>2018-07-11 14:19:36 -0400
commit3b64f761680a7e83f6fc64e90aab9c0923e1cff6 (patch)
tree2c2a13dd67dcf8467e5a46d1b50eae02a4272282
parentUpdate twentysixteen 1.5 (diff)
downloadblogs-gentoo-3b64f761680a7e83f6fc64e90aab9c0923e1cff6.tar.gz
blogs-gentoo-3b64f761680a7e83f6fc64e90aab9c0923e1cff6.tar.bz2
blogs-gentoo-3b64f761680a7e83f6fc64e90aab9c0923e1cff6.zip
Initial commit google-authenticator
-rw-r--r--plugins/google-authenticator/base32.php82
-rw-r--r--plugins/google-authenticator/google-authenticator.php549
-rw-r--r--plugins/google-authenticator/jquery.qrcode.min.js28
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-da_DK.mobin0 -> 2736 bytes
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-da_DK.po113
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-de_DE.mobin0 -> 2565 bytes
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-de_DE.po119
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-es_ES.mobin0 -> 2749 bytes
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-es_ES.po131
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-fr_FR.mobin0 -> 2635 bytes
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-fr_FR.po133
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-it_IT.mobin0 -> 3324 bytes
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-it_IT.po143
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-zh_CN.mobin0 -> 3026 bytes
-rw-r--r--plugins/google-authenticator/lang/google-authenticator-zh_CN.po126
-rw-r--r--plugins/google-authenticator/lang/google-authenticator.pot112
-rw-r--r--plugins/google-authenticator/readme.txt170
-rw-r--r--plugins/google-authenticator/screenshot-1.jpgbin0 -> 28821 bytes
-rw-r--r--plugins/google-authenticator/screenshot-2.jpgbin0 -> 101559 bytes
-rw-r--r--plugins/google-authenticator/screenshot-3.jpgbin0 -> 148800 bytes
-rw-r--r--plugins/google-authenticator/screenshot-4.jpgbin0 -> 64993 bytes
-rw-r--r--plugins/google-authenticator/screenshot-5.jpgbin0 -> 24141 bytes
22 files changed, 1706 insertions, 0 deletions
diff --git a/plugins/google-authenticator/base32.php b/plugins/google-authenticator/base32.php
new file mode 100644
index 00000000..91bd93e9
--- /dev/null
+++ b/plugins/google-authenticator/base32.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * Encode in Base32 based on RFC 4648.
+ * Requires 20% more space than base64
+ * Great for case-insensitive filesystems like Windows and URL's (except for = char which can be excluded using the pad option for urls)
+ *
+ * @package default
+ * @author Bryan Ruiz
+ **/
+class Base32 {
+
+ private static $map = array(
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
+ 'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
+ '=' // padding char
+ );
+
+ private static $flippedMap = array(
+ 'A'=>'0', 'B'=>'1', 'C'=>'2', 'D'=>'3', 'E'=>'4', 'F'=>'5', 'G'=>'6', 'H'=>'7',
+ 'I'=>'8', 'J'=>'9', 'K'=>'10', 'L'=>'11', 'M'=>'12', 'N'=>'13', 'O'=>'14', 'P'=>'15',
+ 'Q'=>'16', 'R'=>'17', 'S'=>'18', 'T'=>'19', 'U'=>'20', 'V'=>'21', 'W'=>'22', 'X'=>'23',
+ 'Y'=>'24', 'Z'=>'25', '2'=>'26', '3'=>'27', '4'=>'28', '5'=>'29', '6'=>'30', '7'=>'31'
+ );
+
+ /**
+ * Use padding false when encoding for urls
+ *
+ * @return base32 encoded string
+ * @author Bryan Ruiz
+ **/
+ public static function encode($input, $padding = true) {
+ if(empty($input)) return "";
+ $input = str_split($input);
+ $binaryString = "";
+ for($i = 0; $i < count($input); $i++) {
+ $binaryString .= str_pad(base_convert(ord($input[$i]), 10, 2), 8, '0', STR_PAD_LEFT);
+ }
+ $fiveBitBinaryArray = str_split($binaryString, 5);
+ $base32 = "";
+ $i=0;
+ while($i < count($fiveBitBinaryArray)) {
+ $base32 .= self::$map[base_convert(str_pad($fiveBitBinaryArray[$i], 5,'0'), 2, 10)];
+ $i++;
+ }
+ if($padding && ($x = strlen($binaryString) % 40) != 0) {
+ if($x == 8) $base32 .= str_repeat(self::$map[32], 6);
+ else if($x == 16) $base32 .= str_repeat(self::$map[32], 4);
+ else if($x == 24) $base32 .= str_repeat(self::$map[32], 3);
+ else if($x == 32) $base32 .= self::$map[32];
+ }
+ return $base32;
+ }
+
+ public static function decode($input) {
+ if(empty($input)) return;
+ $paddingCharCount = substr_count($input, self::$map[32]);
+ $allowedValues = array(6,4,3,1,0);
+ if(!in_array($paddingCharCount, $allowedValues)) return false;
+ for($i=0; $i<4; $i++){
+ if($paddingCharCount == $allowedValues[$i] &&
+ substr($input, -($allowedValues[$i])) != str_repeat(self::$map[32], $allowedValues[$i])) return false;
+ }
+ $input = str_replace('=','', $input);
+ $input = str_split($input);
+ $binaryString = "";
+ for($i=0; $i < count($input); $i = $i+8) {
+ $x = "";
+ if(!in_array($input[$i], self::$map)) return false;
+ for($j=0; $j < 8; $j++) {
+ $x .= str_pad(base_convert(@self::$flippedMap[@$input[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
+ }
+ $eightBits = str_split($x, 8);
+ for($z = 0; $z < count($eightBits); $z++) {
+ $binaryString .= ( ($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48 ) ? $y:"";
+ }
+ }
+ return $binaryString;
+ }
+} \ No newline at end of file
diff --git a/plugins/google-authenticator/google-authenticator.php b/plugins/google-authenticator/google-authenticator.php
new file mode 100644
index 00000000..a2c46d85
--- /dev/null
+++ b/plugins/google-authenticator/google-authenticator.php
@@ -0,0 +1,549 @@
+<?php
+/*
+Plugin Name: Google Authenticator
+Plugin URI: http://henrik.schack.dk/google-authenticator-for-wordpress
+Description: Two-Factor Authentication for WordPress using the Android/iPhone/Blackberry app as One Time Password generator.
+Author: Henrik Schack
+Version: 0.48
+Author URI: http://henrik.schack.dk/
+Compatibility: WordPress 4.5
+Text Domain: google-authenticator
+Domain Path: /lang
+
+----------------------------------------------------------------------------
+
+ Thanks to Bryan Ruiz for his Base32 encode/decode class, found at php.net.
+ Thanks to Tobias Bthge for his major code rewrite and German translation.
+ Thanks to Pascal de Bruijn for his relaxed mode idea.
+ Thanks to Daniel Werl for his usability tips.
+ Thanks to Dion Hulse for his bugfixes.
+ Thanks to Aldo Latino for his Italian translation.
+ Thanks to Kaijia Feng for his Simplified Chinese translation.
+ Thanks to Ian Dunn for fixing some depricated function calls.
+ Thanks to Kimmo Suominen for fixing the iPhone description issue.
+ Thanks to Alex Concha for some security tips.
+ Thanks to Sbastien Prunier for his Spanish and French translations.
+
+----------------------------------------------------------------------------
+
+ Copyright 2013 Henrik Schack (email : henrik@schack.dk)
+
+ This program 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 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+class GoogleAuthenticator {
+
+static $instance; // to store a reference to the plugin, allows other plugins to remove actions
+
+/**
+ * Constructor, entry point of the plugin
+ */
+function __construct() {
+ self::$instance = $this;
+ add_action( 'init', array( $this, 'init' ) );
+}
+
+/**
+ * Initialization, Hooks, and localization
+ */
+function init() {
+ require_once( 'base32.php' );
+
+ add_action( 'login_form', array( $this, 'loginform' ) );
+ add_action( 'login_footer', array( $this, 'loginfooter' ) );
+ add_filter( 'authenticate', array( $this, 'check_otp' ), 50, 3 );
+
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
+ add_action( 'wp_ajax_GoogleAuthenticator_action', array( $this, 'ajax_callback' ) );
+ }
+
+ add_action( 'personal_options_update', array( $this, 'personal_options_update' ) );
+ add_action( 'profile_personal_options', array( $this, 'profile_personal_options' ) );
+ add_action( 'edit_user_profile', array( $this, 'edit_user_profile' ) );
+ add_action( 'edit_user_profile_update', array( $this, 'edit_user_profile_update' ) );
+
+ add_action('admin_enqueue_scripts', array($this, 'add_qrcode_script'));
+
+ load_plugin_textdomain( 'google-authenticator', false, basename( dirname( __FILE__ ) ) . '/lang' );
+}
+
+
+/**
+ * Check the verification code entered by the user.
+ */
+function verify( $secretkey, $thistry, $relaxedmode, $lasttimeslot ) {
+
+ // Did the user enter 6 digits ?
+ if ( strlen( $thistry ) != 6) {
+ return false;
+ } else {
+ $thistry = intval ( $thistry );
+ }
+
+ // If user is running in relaxed mode, we allow more time drifting
+ // 4 min, as opposed to 30 seconds in normal mode.
+ if ( $relaxedmode == 'enabled' ) {
+ $firstcount = -8;
+ $lastcount = 8;
+ } else {
+ $firstcount = -1;
+ $lastcount = 1;
+ }
+
+ $tm = floor( time() / 30 );
+
+ $secretkey=Base32::decode($secretkey);
+ // Keys from 30 seconds before and after are valid aswell.
+ for ($i=$firstcount; $i<=$lastcount; $i++) {
+ // Pack time into binary string
+ $time=chr(0).chr(0).chr(0).chr(0).pack('N*',$tm+$i);
+ // Hash it with users secret key
+ $hm = hash_hmac( 'SHA1', $time, $secretkey, true );
+ // Use last nipple of result as index/offset
+ $offset = ord(substr($hm,-1)) & 0x0F;
+ // grab 4 bytes of the result
+ $hashpart=substr($hm,$offset,4);
+ // Unpak binary value
+ $value=unpack("N",$hashpart);
+ $value=$value[1];
+ // Only 32 bits
+ $value = $value & 0x7FFFFFFF;
+ $value = $value % 1000000;
+ if ( $value === $thistry ) {
+ // Check for replay (Man-in-the-middle) attack.
+ // Since this is not Star Trek, time can only move forward,
+ // meaning current login attempt has to be in the future compared to
+ // last successful login.
+ if ( $lasttimeslot >= ($tm+$i) ) {
+ error_log("Google Authenticator plugin: Man-in-the-middle attack detected (Could also be 2 legit login attempts within the same 30 second period)");
+ return false;
+ }
+ // Return timeslot in which login happened.
+ return $tm+$i;
+ }
+ }
+ return false;
+}
+
+/**
+ * Create a new random secret for the Google Authenticator app.
+ * 16 characters, randomly chosen from the allowed Base32 characters
+ * equals 10 bytes = 80 bits, as 256^10 = 32^16 = 2^80
+ */
+function create_secret() {
+ $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; // allowed characters in Base32
+ $secret = '';
+ for ( $i = 0; $i < 16; $i++ ) {
+ $secret .= substr( $chars, wp_rand( 0, strlen( $chars ) - 1 ), 1 );
+ }
+ return $secret;
+}
+
+/**
+ * Add the script to generate QR codes.
+ */
+function add_qrcode_script() {
+ wp_enqueue_script('jquery');
+ wp_register_script('qrcode_script', plugins_url('jquery.qrcode.min.js', __FILE__),array("jquery"));
+ wp_enqueue_script('qrcode_script');
+}
+
+/**
+ * Add verification code field to login form.
+ */
+function loginform() {
+ echo "\t<p>\n";
+ 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";
+ echo "\t\t<input type=\"text\" name=\"googleotp\" id=\"user_email\" class=\"input\" value=\"\" size=\"20\" style=\"ime-mode: inactive;\" /></label>\n";
+ echo "\t</p>\n";
+}
+
+/**
+ * Disable autocomplete on Google Authenticator code input field.
+ */
+function loginfooter() {
+ echo "\n<script type=\"text/javascript\">\n";
+ echo "\ttry{\n";
+ echo "\t\tdocument.getElementById('user_email').setAttribute('autocomplete','off');\n";
+ echo "\t} catch(e){}\n";
+ echo "</script>\n";
+}
+
+/**
+ * Login form handling.
+ * Check Google Authenticator verification code, if user has been setup to do so.
+ * @param wordpressuser
+ * @return user/loginstatus
+ */
+function check_otp( $user, $username = '', $password = '' ) {
+ // Store result of loginprocess, so far.
+ $userstate = $user;
+
+ // Get information on user, we need this in case an app password has been enabled,
+ // since the $user var only contain an error at this point in the login flow.
+ if ( get_user_by( 'email', $username ) === false ) {
+ $user = get_user_by( 'login', $username );
+ } else {
+ $user = get_user_by( 'email', $username );
+ }
+
+ // Does the user have the Google Authenticator enabled ?
+ if ( isset( $user->ID ) && trim(get_user_option( 'googleauthenticator_enabled', $user->ID ) ) == 'enabled' ) {
+
+ // Get the users secret
+ $GA_secret = trim( get_user_option( 'googleauthenticator_secret', $user->ID ) );
+
+ // Figure out if user is using relaxed mode ?
+ $GA_relaxedmode = trim( get_user_option( 'googleauthenticator_relaxedmode', $user->ID ) );
+
+ // Get the verification code entered by the user trying to login
+ if ( !empty( $_POST['googleotp'] )) { // Prevent PHP notices when using app password login
+ $otp = trim( $_POST[ 'googleotp' ] );
+ } else {
+ $otp = '';
+ }
+ // When was the last successful login performed ?
+ $lasttimeslot = trim( get_user_option( 'googleauthenticator_lasttimeslot', $user->ID ) );
+ // Valid code ?
+ if ( $timeslot = $this->verify( $GA_secret, $otp, $GA_relaxedmode, $lasttimeslot ) ) {
+ // Store the timeslot in which login was successful.
+ update_user_option( $user->ID, 'googleauthenticator_lasttimeslot', $timeslot, true );
+ return $userstate;
+ } else {
+ // No, lets see if an app password is enabled, and this is an XMLRPC / APP login ?
+ if ( trim( get_user_option( 'googleauthenticator_pwdenabled', $user->ID ) ) == 'enabled' && ( defined('XMLRPC_REQUEST') || defined('APP_REQUEST') ) ) {
+ $GA_passwords = json_decode( get_user_option( 'googleauthenticator_passwords', $user->ID ) );
+ $passwordhash = trim($GA_passwords->{'password'} );
+ $usersha1 = sha1( strtoupper( str_replace( ' ', '', $password ) ) );
+ if ( $passwordhash == $usersha1 ) { // ToDo: Remove after some time when users have migrated to new format
+ return new WP_User( $user->ID );
+ // Try the new version based on thee wp_hash_password function
+ } elseif (wp_check_password( strtoupper( str_replace( ' ', '', $password ) ), $passwordhash)) {
+ return new WP_User( $user->ID );
+ } else {
+ // Wrong XMLRPC/APP password !
+ return new WP_Error( 'invalid_google_authenticator_password', __( '<strong>ERROR</strong>: The Google Authenticator password is incorrect.', 'google-authenticator' ) );
+ }
+ } else {
+ return new WP_Error( 'invalid_google_authenticator_token', __( '<strong>ERROR</strong>: The Google Authenticator code is incorrect or has expired.', 'google-authenticator' ) );
+ }
+ }
+ }
+ // Google Authenticator isn't enabled for this account,
+ // just resume normal authentication.
+ return $userstate;
+}
+
+
+/**
+ * Extend personal profile page with Google Authenticator settings.
+ */
+function profile_personal_options() {
+ global $user_id, $is_profile_page;
+
+ // If editing of Google Authenticator settings has been disabled, just return
+ $GA_hidefromuser = trim( get_user_option( 'googleauthenticator_hidefromuser', $user_id ) );
+ if ( $GA_hidefromuser == 'enabled') return;
+
+ $GA_secret = trim( get_user_option( 'googleauthenticator_secret', $user_id ) );
+ $GA_enabled = trim( get_user_option( 'googleauthenticator_enabled', $user_id ) );
+ $GA_relaxedmode = trim( get_user_option( 'googleauthenticator_relaxedmode', $user_id ) );
+ $GA_description = trim( get_user_option( 'googleauthenticator_description', $user_id ) );
+ $GA_pwdenabled = trim( get_user_option( 'googleauthenticator_pwdenabled', $user_id ) );
+ $GA_password = trim( get_user_option( 'googleauthenticator_passwords', $user_id ) );
+
+ // We dont store the generated app password in cleartext so there is no point in trying
+ // to show the user anything except from the fact that a password exists.
+ if ( $GA_password != '' ) {
+ $GA_password = "XXXX XXXX XXXX XXXX";
+ }
+
+ // In case the user has no secret ready (new install), we create one.
+ if ( '' == $GA_secret ) {
+ $GA_secret = $this->create_secret();
+ }
+
+ // Use "WordPress Blog" as default description
+ if ( '' == $GA_description ) {
+ $GA_description = __( 'WordPressBlog', 'google-authenticator' );
+ }
+
+ echo "<h3>".__( 'Google Authenticator Settings', 'google-authenticator' )."</h3>\n";
+
+ echo "<table class=\"form-table\">\n";
+ echo "<tbody>\n";
+ echo "<tr>\n";
+ echo "<th scope=\"row\">".__( 'Active', 'google-authenticator' )."</th>\n";
+ echo "<td>\n";
+ echo "<input name=\"GA_enabled\" id=\"GA_enabled\" class=\"tog\" type=\"checkbox\"" . checked( $GA_enabled, 'enabled', false ) . "/>\n";
+ echo "</td>\n";
+ echo "</tr>\n";
+
+ if ( $is_profile_page || IS_PROFILE_PAGE ) {
+ echo "<tr>\n";
+ echo "<th scope=\"row\">".__( 'Relaxed mode', 'google-authenticator' )."</th>\n";
+ echo "<td>\n";
+ 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";
+ echo "</td>\n";
+ echo "</tr>\n";
+
+ echo "<tr>\n";
+ echo "<th><label for=\"GA_description\">".__('Description','google-authenticator')."</label></th>\n";
+ 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";
+ echo "</tr>\n";
+
+ echo "<tr>\n";
+ echo "<th><label for=\"GA_secret\">".__('Secret','google-authenticator')."</label></th>\n";
+ echo "<td>\n";
+ echo "<input name=\"GA_secret\" id=\"GA_secret\" value=\"{$GA_secret}\" readonly=\"readonly\" type=\"text\" size=\"25\" />";
+ echo "<input name=\"GA_newsecret\" id=\"GA_newsecret\" value=\"".__("Create new secret",'google-authenticator')."\" type=\"button\" class=\"button\" />";
+ echo "<input name=\"show_qr\" id=\"show_qr\" value=\"".__("Show/Hide QR code",'google-authenticator')."\" type=\"button\" class=\"button\" onclick=\"ShowOrHideQRCode();\" />";
+ echo "</td>\n";
+ echo "</tr>\n";
+
+ echo "<tr>\n";
+ echo "<th></th>\n";
+ echo "<td><div id=\"GA_QR_INFO\" style=\"display: none\" >";
+ echo "<div id=\"GA_QRCODE\"/></div>";
+
+ echo '<span class="description"><br/> ' . __( 'Scan this with the Google Authenticator app.', 'google-authenticator' ) . '</span>';
+ echo "</div></td>\n";
+ echo "</tr>\n";
+
+ echo "<tr>\n";
+ echo "<th scope=\"row\">".__( 'Enable App password', 'google-authenticator' )."</th>\n";
+ echo "<td>\n";
+ 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";
+ echo "</td>\n";
+ echo "</tr>\n";
+
+ echo "<tr>\n";
+ echo "<th></th>\n";
+ echo "<td>\n";
+ echo "<input name=\"GA_password\" id=\"GA_password\" readonly=\"readonly\" value=\"".$GA_password."\" type=\"text\" size=\"25\" />";
+ echo "<input name=\"GA_createpassword\" id=\"GA_createpassword\" value=\"".__("Create new password",'google-authenticator')."\" type=\"button\" class=\"button\" />";
+ 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";
+ echo "</td>\n";
+ echo "</tr>\n";
+ }
+
+ echo "</tbody></table>\n";
+ echo "<script type=\"text/javascript\">\n";
+ echo "var GAnonce='".wp_create_nonce('GoogleAuthenticatoraction')."';\n";
+
+ echo <<<ENDOFJS
+ //Create new secret and display it
+ jQuery('#GA_newsecret').bind('click', function() {
+ // Remove existing QRCode
+ jQuery('#GA_QRCODE').html("");
+ var data=new Object();
+ data['action'] = 'GoogleAuthenticator_action';
+ data['nonce'] = GAnonce;
+ jQuery.post(ajaxurl, data, function(response) {
+ jQuery('#GA_secret').val(response['new-secret']);
+ var qrcode="otpauth://totp/WordPress:"+escape(jQuery('#GA_description').val())+"?secret="+jQuery('#GA_secret').val()+"&issuer=WordPress";
+ jQuery('#GA_QRCODE').qrcode(qrcode);
+ jQuery('#GA_QR_INFO').show('slow');
+ });
+ });
+
+ // If the user starts modifying the description, hide the qrcode
+ jQuery('#GA_description').bind('focus blur change keyup', function() {
+ // Only remove QR Code if it's visible
+ if (jQuery('#GA_QR_INFO').is(':visible')) {
+ jQuery('#GA_QR_INFO').hide('slow');
+ jQuery('#GA_QRCODE').html("");
+ }
+ });
+
+ // Create new app password
+ jQuery('#GA_createpassword').bind('click',function() {
+ var data=new Object();
+ data['action'] = 'GoogleAuthenticator_action';
+ data['nonce'] = GAnonce;
+ data['save'] = 1;
+ jQuery.post(ajaxurl, data, function(response) {
+ jQuery('#GA_password').val(response['new-secret'].match(new RegExp(".{0,4}","g")).join(' '));
+ jQuery('#GA_passworddesc').show();
+ });
+ });
+
+ jQuery('#GA_enabled').bind('change',function() {
+ GoogleAuthenticator_apppasswordcontrol();
+ });
+
+ jQuery(document).ready(function() {
+ jQuery('#GA_passworddesc').hide();
+ GoogleAuthenticator_apppasswordcontrol();
+ });
+
+ function GoogleAuthenticator_apppasswordcontrol() {
+ if (jQuery('#GA_enabled').is(':checked')) {
+ jQuery('#GA_pwdenabled').removeAttr('disabled');
+ jQuery('#GA_createpassword').removeAttr('disabled');
+ } else {
+ jQuery('#GA_pwdenabled').removeAttr('checked')
+ jQuery('#GA_pwdenabled').attr('disabled', true);
+ jQuery('#GA_createpassword').attr('disabled', true);
+ }
+ }
+
+ function ShowOrHideQRCode() {
+ if (jQuery('#GA_QR_INFO').is(':hidden')) {
+ var qrcode="otpauth://totp/WordPress:"+escape(jQuery('#GA_description').val())+"?secret="+jQuery('#GA_secret').val()+"&issuer=WordPress";
+ jQuery('#GA_QRCODE').qrcode(qrcode);
+ jQuery('#GA_QR_INFO').show('slow');
+ } else {
+ jQuery('#GA_QR_INFO').hide('slow');
+ jQuery('#GA_QRCODE').html("");
+ }
+ }
+</script>
+ENDOFJS;
+}
+
+/**
+ * Form handling of Google Authenticator options added to personal profile page (user editing his own profile)
+ */
+function personal_options_update() {
+ global $user_id;
+
+ // If editing of Google Authenticator settings has been disabled, just return
+ $GA_hidefromuser = trim( get_user_option( 'googleauthenticator_hidefromuser', $user_id ) );
+ if ( $GA_hidefromuser == 'enabled') return;
+
+
+ $GA_enabled = ! empty( $_POST['GA_enabled'] );
+ $GA_description = trim( sanitize_text_field($_POST['GA_description'] ) );
+ $GA_relaxedmode = ! empty( $_POST['GA_relaxedmode'] );
+ $GA_secret = trim( $_POST['GA_secret'] );
+ $GA_pwdenabled = ! empty( $_POST['GA_pwdenabled'] );
+ $GA_password = str_replace(' ', '', trim( $_POST['GA_password'] ) );
+
+ if ( ! $GA_enabled ) {
+ $GA_enabled = 'disabled';
+ } else {
+ $GA_enabled = 'enabled';
+ }
+
+ if ( ! $GA_relaxedmode ) {
+ $GA_relaxedmode = 'disabled';
+ } else {
+ $GA_relaxedmode = 'enabled';
+ }
+
+
+ if ( ! $GA_pwdenabled ) {
+ $GA_pwdenabled = 'disabled';
+ } else {
+ $GA_pwdenabled = 'enabled';
+ }
+
+ // Only store password if a new one has been generated.
+ if (strtoupper($GA_password) != 'XXXXXXXXXXXXXXXX' ) {
+ // Store the password in a format that can be expanded easily later on if needed.
+ $GA_password = array( 'appname' => 'Default', 'password' => wp_hash_password( $GA_password ) );
+ update_user_option( $user_id, 'googleauthenticator_passwords', json_encode( $GA_password ), true );
+ }
+
+ update_user_option( $user_id, 'googleauthenticator_enabled', $GA_enabled, true );
+ update_user_option( $user_id, 'googleauthenticator_description', $GA_description, true );
+ update_user_option( $user_id, 'googleauthenticator_relaxedmode', $GA_relaxedmode, true );
+ update_user_option( $user_id, 'googleauthenticator_secret', $GA_secret, true );
+ update_user_option( $user_id, 'googleauthenticator_pwdenabled', $GA_pwdenabled, true );
+
+}
+
+/**
+ * Extend profile page with ability to enable/disable Google Authenticator authentication requirement.
+ * Used by an administrator when editing other users.
+ */
+function edit_user_profile() {
+ global $user_id;
+ $GA_enabled = trim( get_user_option( 'googleauthenticator_enabled', $user_id ) );
+ $GA_hidefromuser = trim( get_user_option( 'googleauthenticator_hidefromuser', $user_id ) );
+ echo "<h3>".__('Google Authenticator Settings','google-authenticator')."</h3>\n";
+ echo "<table class=\"form-table\">\n";
+ echo "<tbody>\n";
+
+ echo "<tr>\n";
+ echo "<th scope=\"row\">".__('Hide settings from user','google-authenticator')."</th>\n";
+ echo "<td>\n";
+ echo "<div><input name=\"GA_hidefromuser\" id=\"GA_hidefromuser\" class=\"tog\" type=\"checkbox\"" . checked( $GA_hidefromuser, 'enabled', false ) . "/>\n";
+ echo "</td>\n";
+ echo "</tr>\n";
+
+ echo "<tr>\n";
+ echo "<th scope=\"row\">".__('Active','google-authenticator')."</th>\n";
+ echo "<td>\n";
+ echo "<div><input name=\"GA_enabled\" id=\"GA_enabled\" class=\"tog\" type=\"checkbox\"" . checked( $GA_enabled, 'enabled', false ) . "/>\n";
+ echo "</td>\n";
+ echo "</tr>\n";
+
+ echo "</tbody>\n";
+ echo "</table>\n";
+}
+
+/**
+ * Form handling of Google Authenticator options on edit profile page (admin user editing other user)
+ */
+function edit_user_profile_update() {
+ global $user_id;
+
+ $GA_enabled = ! empty( $_POST['GA_enabled'] );
+ $GA_hidefromuser = ! empty( $_POST['GA_hidefromuser'] );
+
+ if ( ! $GA_enabled ) {
+ $GA_enabled = 'disabled';
+ } else {
+ $GA_enabled = 'enabled';
+ }
+
+ if ( ! $GA_hidefromuser ) {
+ $GA_hidefromuser = 'disabled';
+ } else {
+ $GA_hidefromuser = 'enabled';
+ }
+
+ update_user_option( $user_id, 'googleauthenticator_enabled', $GA_enabled, true );
+ update_user_option( $user_id, 'googleauthenticator_hidefromuser', $GA_hidefromuser, true );
+
+}
+
+
+/**
+* AJAX callback function used to generate new secret
+*/
+function ajax_callback() {
+ global $user_id;
+
+ // Some AJAX security.
+ check_ajax_referer( 'GoogleAuthenticatoraction', 'nonce' );
+
+ // Create new secret.
+ $secret = $this->create_secret();
+
+ $result = array( 'new-secret' => $secret );
+ header( 'Content-Type: application/json' );
+ echo json_encode( $result );
+
+ // die() is required to return a proper result
+ die();
+}
+
+} // end class
+
+$google_authenticator = new GoogleAuthenticator;
+?>
diff --git a/plugins/google-authenticator/jquery.qrcode.min.js b/plugins/google-authenticator/jquery.qrcode.min.js
new file mode 100644
index 00000000..fe9680e6
--- /dev/null
+++ b/plugins/google-authenticator/jquery.qrcode.min.js
@@ -0,0 +1,28 @@
+(function(r){r.fn.qrcode=function(h){var s;function u(a){this.mode=s;this.data=a}function o(a,c){this.typeNumber=a;this.errorCorrectLevel=c;this.modules=null;this.moduleCount=0;this.dataCache=null;this.dataList=[]}function q(a,c){if(void 0==a.length)throw Error(a.length+"/"+c);for(var d=0;d<a.length&&0==a[d];)d++;this.num=Array(a.length-d+c);for(var b=0;b<a.length-d;b++)this.num[b]=a[b+d]}function p(a,c){this.totalCount=a;this.dataCount=c}function t(){this.buffer=[];this.length=0}u.prototype={getLength:function(){return this.data.length},
+write:function(a){for(var c=0;c<this.data.length;c++)a.put(this.data.charCodeAt(c),8)}};o.prototype={addData:function(a){this.dataList.push(new u(a));this.dataCache=null},isDark:function(a,c){if(0>a||this.moduleCount<=a||0>c||this.moduleCount<=c)throw Error(a+","+c);return this.modules[a][c]},getModuleCount:function(){return this.moduleCount},make:function(){if(1>this.typeNumber){for(var a=1,a=1;40>a;a++){for(var c=p.getRSBlocks(a,this.errorCorrectLevel),d=new t,b=0,e=0;e<c.length;e++)b+=c[e].dataCount;
+for(e=0;e<this.dataList.length;e++)c=this.dataList[e],d.put(c.mode,4),d.put(c.getLength(),j.getLengthInBits(c.mode,a)),c.write(d);if(d.getLengthInBits()<=8*b)break}this.typeNumber=a}this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17;this.modules=Array(this.moduleCount);for(var d=0;d<this.moduleCount;d++){this.modules[d]=Array(this.moduleCount);for(var b=0;b<this.moduleCount;b++)this.modules[d][b]=null}this.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-
+7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(a,c);7<=this.typeNumber&&this.setupTypeNumber(a);null==this.dataCache&&(this.dataCache=o.createData(this.typeNumber,this.errorCorrectLevel,this.dataList));this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,c){for(var d=-1;7>=d;d++)if(!(-1>=a+d||this.moduleCount<=a+d))for(var b=-1;7>=b;b++)-1>=c+b||this.moduleCount<=c+b||(this.modules[a+d][c+b]=
+0<=d&&6>=d&&(0==b||6==b)||0<=b&&6>=b&&(0==d||6==d)||2<=d&&4>=d&&2<=b&&4>=b?!0:!1)},getBestMaskPattern:function(){for(var a=0,c=0,d=0;8>d;d++){this.makeImpl(!0,d);var b=j.getLostPoint(this);if(0==d||a>b)a=b,c=d}return c},createMovieClip:function(a,c,d){a=a.createEmptyMovieClip(c,d);this.make();for(c=0;c<this.modules.length;c++)for(var d=1*c,b=0;b<this.modules[c].length;b++){var e=1*b;this.modules[c][b]&&(a.beginFill(0,100),a.moveTo(e,d),a.lineTo(e+1,d),a.lineTo(e+1,d+1),a.lineTo(e,d+1),a.endFill())}return a},
+setupTimingPattern:function(){for(var a=8;a<this.moduleCount-8;a++)null==this.modules[a][6]&&(this.modules[a][6]=0==a%2);for(a=8;a<this.moduleCount-8;a++)null==this.modules[6][a]&&(this.modules[6][a]=0==a%2)},setupPositionAdjustPattern:function(){for(var a=j.getPatternPosition(this.typeNumber),c=0;c<a.length;c++)for(var d=0;d<a.length;d++){var b=a[c],e=a[d];if(null==this.modules[b][e])for(var f=-2;2>=f;f++)for(var i=-2;2>=i;i++)this.modules[b+f][e+i]=-2==f||2==f||-2==i||2==i||0==f&&0==i?!0:!1}},setupTypeNumber:function(a){for(var c=
+j.getBCHTypeNumber(this.typeNumber),d=0;18>d;d++){var b=!a&&1==(c>>d&1);this.modules[Math.floor(d/3)][d%3+this.moduleCount-8-3]=b}for(d=0;18>d;d++)b=!a&&1==(c>>d&1),this.modules[d%3+this.moduleCount-8-3][Math.floor(d/3)]=b},setupTypeInfo:function(a,c){for(var d=j.getBCHTypeInfo(this.errorCorrectLevel<<3|c),b=0;15>b;b++){var e=!a&&1==(d>>b&1);6>b?this.modules[b][8]=e:8>b?this.modules[b+1][8]=e:this.modules[this.moduleCount-15+b][8]=e}for(b=0;15>b;b++)e=!a&&1==(d>>b&1),8>b?this.modules[8][this.moduleCount-
+b-1]=e:9>b?this.modules[8][15-b-1+1]=e:this.modules[8][15-b-1]=e;this.modules[this.moduleCount-8][8]=!a},mapData:function(a,c){for(var d=-1,b=this.moduleCount-1,e=7,f=0,i=this.moduleCount-1;0<i;i-=2)for(6==i&&i--;;){for(var g=0;2>g;g++)if(null==this.modules[b][i-g]){var n=!1;f<a.length&&(n=1==(a[f]>>>e&1));j.getMask(c,b,i-g)&&(n=!n);this.modules[b][i-g]=n;e--; -1==e&&(f++,e=7)}b+=d;if(0>b||this.moduleCount<=b){b-=d;d=-d;break}}}};o.PAD0=236;o.PAD1=17;o.createData=function(a,c,d){for(var c=p.getRSBlocks(a,
+c),b=new t,e=0;e<d.length;e++){var f=d[e];b.put(f.mode,4);b.put(f.getLength(),j.getLengthInBits(f.mode,a));f.write(b)}for(e=a=0;e<c.length;e++)a+=c[e].dataCount;if(b.getLengthInBits()>8*a)throw Error("code length overflow. ("+b.getLengthInBits()+">"+8*a+")");for(b.getLengthInBits()+4<=8*a&&b.put(0,4);0!=b.getLengthInBits()%8;)b.putBit(!1);for(;!(b.getLengthInBits()>=8*a);){b.put(o.PAD0,8);if(b.getLengthInBits()>=8*a)break;b.put(o.PAD1,8)}return o.createBytes(b,c)};o.createBytes=function(a,c){for(var d=
+0,b=0,e=0,f=Array(c.length),i=Array(c.length),g=0;g<c.length;g++){var n=c[g].dataCount,h=c[g].totalCount-n,b=Math.max(b,n),e=Math.max(e,h);f[g]=Array(n);for(var k=0;k<f[g].length;k++)f[g][k]=255&a.buffer[k+d];d+=n;k=j.getErrorCorrectPolynomial(h);n=(new q(f[g],k.getLength()-1)).mod(k);i[g]=Array(k.getLength()-1);for(k=0;k<i[g].length;k++)h=k+n.getLength()-i[g].length,i[g][k]=0<=h?n.get(h):0}for(k=g=0;k<c.length;k++)g+=c[k].totalCount;d=Array(g);for(k=n=0;k<b;k++)for(g=0;g<c.length;g++)k<f[g].length&&
+(d[n++]=f[g][k]);for(k=0;k<e;k++)for(g=0;g<c.length;g++)k<i[g].length&&(d[n++]=i[g][k]);return d};s=4;for(var j={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,
+78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(a){for(var c=a<<10;0<=j.getBCHDigit(c)-j.getBCHDigit(j.G15);)c^=j.G15<<j.getBCHDigit(c)-j.getBCHDigit(j.G15);return(a<<10|c)^j.G15_MASK},getBCHTypeNumber:function(a){for(var c=a<<12;0<=j.getBCHDigit(c)-
+j.getBCHDigit(j.G18);)c^=j.G18<<j.getBCHDigit(c)-j.getBCHDigit(j.G18);return a<<12|c},getBCHDigit:function(a){for(var c=0;0!=a;)c++,a>>>=1;return c},getPatternPosition:function(a){return j.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,c,d){switch(a){case 0:return 0==(c+d)%2;case 1:return 0==c%2;case 2:return 0==d%3;case 3:return 0==(c+d)%3;case 4:return 0==(Math.floor(c/2)+Math.floor(d/3))%2;case 5:return 0==c*d%2+c*d%3;case 6:return 0==(c*d%2+c*d%3)%2;case 7:return 0==(c*d%3+(c+d)%2)%2;default:throw Error("bad maskPattern:"+
+a);}},getErrorCorrectPolynomial:function(a){for(var c=new q([1],0),d=0;d<a;d++)c=c.multiply(new q([1,l.gexp(d)],0));return c},getLengthInBits:function(a,c){if(1<=c&&10>c)switch(a){case 1:return 10;case 2:return 9;case s:return 8;case 8:return 8;default:throw Error("mode:"+a);}else if(27>c)switch(a){case 1:return 12;case 2:return 11;case s:return 16;case 8:return 10;default:throw Error("mode:"+a);}else if(41>c)switch(a){case 1:return 14;case 2:return 13;case s:return 16;case 8:return 12;default:throw Error("mode:"+
+a);}else throw Error("type:"+c);},getLostPoint:function(a){for(var c=a.getModuleCount(),d=0,b=0;b<c;b++)for(var e=0;e<c;e++){for(var f=0,i=a.isDark(b,e),g=-1;1>=g;g++)if(!(0>b+g||c<=b+g))for(var h=-1;1>=h;h++)0>e+h||c<=e+h||0==g&&0==h||i==a.isDark(b+g,e+h)&&f++;5<f&&(d+=3+f-5)}for(b=0;b<c-1;b++)for(e=0;e<c-1;e++)if(f=0,a.isDark(b,e)&&f++,a.isDark(b+1,e)&&f++,a.isDark(b,e+1)&&f++,a.isDark(b+1,e+1)&&f++,0==f||4==f)d+=3;for(b=0;b<c;b++)for(e=0;e<c-6;e++)a.isDark(b,e)&&!a.isDark(b,e+1)&&a.isDark(b,e+
+2)&&a.isDark(b,e+3)&&a.isDark(b,e+4)&&!a.isDark(b,e+5)&&a.isDark(b,e+6)&&(d+=40);for(e=0;e<c;e++)for(b=0;b<c-6;b++)a.isDark(b,e)&&!a.isDark(b+1,e)&&a.isDark(b+2,e)&&a.isDark(b+3,e)&&a.isDark(b+4,e)&&!a.isDark(b+5,e)&&a.isDark(b+6,e)&&(d+=40);for(e=f=0;e<c;e++)for(b=0;b<c;b++)a.isDark(b,e)&&f++;a=Math.abs(100*f/c/c-50)/5;return d+10*a}},l={glog:function(a){if(1>a)throw Error("glog("+a+")");return l.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;256<=a;)a-=255;return l.EXP_TABLE[a]},EXP_TABLE:Array(256),
+LOG_TABLE:Array(256)},m=0;8>m;m++)l.EXP_TABLE[m]=1<<m;for(m=8;256>m;m++)l.EXP_TABLE[m]=l.EXP_TABLE[m-4]^l.EXP_TABLE[m-5]^l.EXP_TABLE[m-6]^l.EXP_TABLE[m-8];for(m=0;255>m;m++)l.LOG_TABLE[l.EXP_TABLE[m]]=m;q.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var c=Array(this.getLength()+a.getLength()-1),d=0;d<this.getLength();d++)for(var b=0;b<a.getLength();b++)c[d+b]^=l.gexp(l.glog(this.get(d))+l.glog(a.get(b)));return new q(c,0)},mod:function(a){if(0>
+this.getLength()-a.getLength())return this;for(var c=l.glog(this.get(0))-l.glog(a.get(0)),d=Array(this.getLength()),b=0;b<this.getLength();b++)d[b]=this.get(b);for(b=0;b<a.getLength();b++)d[b]^=l.gexp(l.glog(a.get(b))+c);return(new q(d,0)).mod(a)}};p.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],
+[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,
+116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,
+43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,
+3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,
+55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,
+45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];p.getRSBlocks=function(a,c){var d=p.getRsBlockTable(a,c);if(void 0==d)throw Error("bad rs block @ typeNumber:"+a+"/errorCorrectLevel:"+c);for(var b=d.length/3,e=[],f=0;f<b;f++)for(var h=d[3*f+0],g=d[3*f+1],j=d[3*f+2],l=0;l<h;l++)e.push(new p(g,j));return e};p.getRsBlockTable=function(a,c){switch(c){case 1:return p.RS_BLOCK_TABLE[4*(a-1)+0];case 0:return p.RS_BLOCK_TABLE[4*(a-1)+1];case 3:return p.RS_BLOCK_TABLE[4*
+(a-1)+2];case 2:return p.RS_BLOCK_TABLE[4*(a-1)+3]}};t.prototype={get:function(a){return 1==(this.buffer[Math.floor(a/8)]>>>7-a%8&1)},put:function(a,c){for(var d=0;d<c;d++)this.putBit(1==(a>>>c-d-1&1))},getLengthInBits:function(){return this.length},putBit:function(a){var c=Math.floor(this.length/8);this.buffer.length<=c&&this.buffer.push(0);a&&(this.buffer[c]|=128>>>this.length%8);this.length++}};"string"===typeof h&&(h={text:h});h=r.extend({},{render:"canvas",width:256,height:256,typeNumber:-1,
+correctLevel:2,background:"#ffffff",foreground:"#000000"},h);return this.each(function(){var a;if("canvas"==h.render){a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();var c=document.createElement("canvas");c.width=h.width;c.height=h.height;for(var d=c.getContext("2d"),b=h.width/a.getModuleCount(),e=h.height/a.getModuleCount(),f=0;f<a.getModuleCount();f++)for(var i=0;i<a.getModuleCount();i++){d.fillStyle=a.isDark(f,i)?h.foreground:h.background;var g=Math.ceil((i+1)*b)-Math.floor(i*b),
+j=Math.ceil((f+1)*b)-Math.floor(f*b);d.fillRect(Math.round(i*b),Math.round(f*e),g,j)}}else{a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();c=r("<table></table>").css("width",h.width+"px").css("height",h.height+"px").css("border","0px").css("border-collapse","collapse").css("background-color",h.background);d=h.width/a.getModuleCount();b=h.height/a.getModuleCount();for(e=0;e<a.getModuleCount();e++){f=r("<tr></tr>").css("height",b+"px").appendTo(c);for(i=0;i<a.getModuleCount();i++)r("<td></td>").css("width",
+d+"px").css("background-color",a.isDark(e,i)?h.foreground:h.background).appendTo(f)}}a=c;jQuery(a).appendTo(this)})}})(jQuery);
diff --git a/plugins/google-authenticator/lang/google-authenticator-da_DK.mo b/plugins/google-authenticator/lang/google-authenticator-da_DK.mo
new file mode 100644
index 00000000..d4b4b1fd
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-da_DK.mo
Binary files differ
diff --git a/plugins/google-authenticator/lang/google-authenticator-da_DK.po b/plugins/google-authenticator/lang/google-authenticator-da_DK.po
new file mode 100644
index 00000000..28fe9911
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-da_DK.po
@@ -0,0 +1,113 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Google Authenticator\n"
+"POT-Creation-Date: 2014-01-11 08:17+0100\n"
+"PO-Revision-Date: 2014-01-11 08:20+0100\n"
+"Last-Translator: Henrik Schack <henrik@schack.dk>\n"
+"Language-Team: \n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.6.3\n"
+"X-Poedit-Basepath: ..\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
+"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
+"_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SearchPath-0: .\n"
+
+#: google-authenticator.php:166
+msgid ""
+"If you don't have Google Authenticator enabled for your WordPress account, "
+"leave this field empty."
+msgstr ""
+"Hvis ikke du har aktiveret Google Authenticator for din konto, så lad være "
+"med at skrive noget her."
+
+#: google-authenticator.php:166
+msgid "Google Authenticator code"
+msgstr "Google Authenticator kode"
+
+#: google-authenticator.php:231
+msgid "<strong>ERROR</strong>: The Google Authenticator password is incorrect."
+msgstr "<strong>ERROR</strong>: Google Authenticator kodeordet er forkert."
+
+#: google-authenticator.php:234
+msgid ""
+"<strong>ERROR</strong>: The Google Authenticator code is incorrect or has "
+"expired."
+msgstr ""
+"<strong>ERROR</strong>: Google Authenticator koden er forkert eller udløbet."
+
+#: google-authenticator.php:274
+msgid "WordPressBlog"
+msgstr "WordPressBlog"
+
+#: google-authenticator.php:277 google-authenticator.php:469
+msgid "Google Authenticator Settings"
+msgstr "Google Authenticator indstillinger"
+
+#: google-authenticator.php:282 google-authenticator.php:481
+msgid "Active"
+msgstr "Aktiv"
+
+#: google-authenticator.php:290
+msgid "Relaxed mode"
+msgstr "Afslappet tilstand"
+
+#: google-authenticator.php:292
+msgid ""
+" Relaxed mode allows for more time drifting on your phone clock (&#177;4 "
+"min)."
+msgstr ""
+"Afslappet tilstand tillader mere upræcis tid på din telefon (&#177;4 min)."
+
+#: google-authenticator.php:297
+msgid "Description"
+msgstr "Beskrivelse"
+
+#: google-authenticator.php:298
+msgid ""
+" Description that you'll see in the Google Authenticator app on your phone."
+msgstr "Beskrivelsen du vil se i Google Authenticator app'en på din telefon."
+
+#: google-authenticator.php:302
+msgid "Secret"
+msgstr "Hemmelig kode"
+
+#: google-authenticator.php:305
+msgid "Create new secret"
+msgstr "Opret ny hemmelig kode"
+
+#: google-authenticator.php:306
+msgid "Show/Hide QR code"
+msgstr "Vis/Gem QR kode"
+
+#: google-authenticator.php:315
+msgid "Scan this with the Google Authenticator app."
+msgstr "Scan dette med Google Authenticator app'en."
+
+#: google-authenticator.php:320
+msgid "Enable App password"
+msgstr "Aktiver app kodeord"
+
+#: google-authenticator.php:322
+msgid " Enabling an App password will decrease your overall login security."
+msgstr ""
+"Aktiverer du app kodeords featuren, påvirker det din sikkerhed generelt."
+
+#: google-authenticator.php:330
+msgid "Create new password"
+msgstr "Opret nyt kodeord"
+
+#: google-authenticator.php:331
+msgid ""
+" Password is not stored in cleartext, this is your only chance to see it."
+msgstr ""
+"Kodeordet gemmes ikke i klartekst, dette er din eneste chance for at se det."
+
+#: google-authenticator.php:474
+msgid "Hide settings from user"
+msgstr "Skjul indstillinger for bruger"
diff --git a/plugins/google-authenticator/lang/google-authenticator-de_DE.mo b/plugins/google-authenticator/lang/google-authenticator-de_DE.mo
new file mode 100644
index 00000000..3ac64c79
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-de_DE.mo
Binary files differ
diff --git a/plugins/google-authenticator/lang/google-authenticator-de_DE.po b/plugins/google-authenticator/lang/google-authenticator-de_DE.po
new file mode 100644
index 00000000..66afca41
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-de_DE.po
@@ -0,0 +1,119 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Google Authenticator 0.30\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/google-authenticator\n"
+"POT-Creation-Date: 2011-05-17 19:38:36+00:00\n"
+"PO-Revision-Date: 2011-06-25 16:20+0100\n"
+"Last-Translator: Tobias Bäthge <wordpress@tobias.baethge.com>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Poedit-Language: \n"
+"X-Poedit-Country: \n"
+"X-Poedit-SourceCharset: utf-8\n"
+"X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;\n"
+"X-Poedit-Basepath: \n"
+"X-Poedit-Bookmarks: \n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Textdomain-Support: yes"
+
+#: google-authenticator.php:118
+#@ google-authenticator
+msgid "Google Authenticator code"
+msgstr "&quot;Google Authenticator&quot;-Code"
+
+#: google-authenticator.php:172
+#: google-authenticator.php:267
+#@ google-authenticator
+msgid "Active"
+msgstr "Aktivieren"
+
+#: google-authenticator.php:184
+#@ google-authenticator
+msgid "Description"
+msgstr "Beschreibung"
+
+#: google-authenticator.php:189
+#@ google-authenticator
+msgid "Secret"
+msgstr "Geheimschlüssel"
+
+#: google-authenticator.php:192
+#@ google-authenticator
+msgid "Create new secret"
+msgstr "Neuen Geheimschlüssel erzeugen"
+
+#: google-authenticator.php:193
+#@ google-authenticator
+msgid "Show/Hide QR code"
+msgstr "QR-Code anzeigen/verstecken"
+
+#. translators: plugin header field 'Name'
+#: google-authenticator.php:0
+#@ google-authenticator
+msgid "Google Authenticator"
+msgstr "Google Authenticator"
+
+#. translators: plugin header field 'PluginURI'
+#: google-authenticator.php:0
+#@ google-authenticator
+msgid "http://henrik.schack.dk/google-authenticator-for-wordpress"
+msgstr "http://henrik.schack.dk/google-authenticator-for-wordpress"
+
+#. translators: plugin header field 'Author'
+#: google-authenticator.php:0
+#@ google-authenticator
+msgid "Henrik Schack"
+msgstr "Henrik Schack"
+
+#. translators: plugin header field 'AuthorURI'
+#: google-authenticator.php:0
+#@ google-authenticator
+msgid "http://henrik.schack.dk/"
+msgstr "http://henrik.schack.dk/"
+
+#. translators: plugin header field 'Version'
+#: google-authenticator.php:0
+#@ google-authenticator
+msgid "0.30"
+msgstr "0.30"
+
+#: google-authenticator.php:143
+#@ google-authenticator
+msgid "<strong>ERROR</strong>: The Google Authenticator code is incorrect or has expired."
+msgstr "<strong>FEHLER</strong>: Der eingegebene &quot;Google Authenticator&quot;-Code ist falsch oder abgelaufen."
+
+#: google-authenticator.php:165
+#@ google-authenticator
+msgid "WordPress Blog"
+msgstr "WordPress-Blog"
+
+#: google-authenticator.php:167
+#: google-authenticator.php:263
+#@ google-authenticator
+msgid "Google Authenticator Settings"
+msgstr "Einstellungen zu Google Authenticator"
+
+#: google-authenticator.php:201
+#@ google-authenticator
+msgid "Scan this with the Google Authenticator app."
+msgstr "Scanne diesen QR-Code mit der &quot;Google Authenticator&quot;-App deines Smartphones."
+
+#: google-authenticator.php:118
+#@ google-authenticator
+msgid "If you don't have Google Authenticator enabled for your WordPress account, leave this field empty."
+msgstr "Falls die Nutzung von &quot;Google Authenticator&quot; für dieses WordPress-Konto nicht aktiviert ist, dieses Feld leer lassen."
+
+#: google-authenticator.php:185
+#@ google-authenticator
+msgid " Description that you'll see in the Google Authenticator app on your phone."
+msgstr "Beschreibung, die in der &quot;Google Authenticator&quot;-App auf dem Smartphone angezeigt wird."
+
+#. translators: plugin header field 'Description'
+#: google-authenticator.php:0
+#@ google-authenticator
+msgid "Two-Factor Authentication for WordPress using the Android/iPhone/Blackberry app as One Time Password generator."
+msgstr "Zwei-Faktor-Authentifizierung für WordPress mit der &quot;Google Authenticator&quot;-App für Android/iPhone/Blackberry"
+
diff --git a/plugins/google-authenticator/lang/google-authenticator-es_ES.mo b/plugins/google-authenticator/lang/google-authenticator-es_ES.mo
new file mode 100644
index 00000000..5bf1304b
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-es_ES.mo
Binary files differ
diff --git a/plugins/google-authenticator/lang/google-authenticator-es_ES.po b/plugins/google-authenticator/lang/google-authenticator-es_ES.po
new file mode 100644
index 00000000..ce9ab6aa
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-es_ES.po
@@ -0,0 +1,131 @@
+# Copyright (C) 2010 Google Authenticator
+# This file is distributed under the same license as the Google Authenticator package.
+msgid ""
+msgstr ""
+"Project-Id-Version: Google Authenticator 0.37\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/google-authenticator\n"
+"POT-Creation-Date: 2011-08-21 14:25:45+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2014-01-11 10:07+0100\n"
+"Last-Translator: \n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"X-Generator: Poedit 1.6.3\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Language: es_ES\n"
+
+#: google-authenticator.php:131
+msgid ""
+"If you don't have Google Authenticator enabled for your WordPress account, "
+"leave this field empty."
+msgstr ""
+"Si no tiene Google Authenticator habilitado en su cuenta de WordPress, deje "
+"este campo vacío."
+
+#: google-authenticator.php:131
+msgid "Google Authenticator code"
+msgstr "Código Google Authenticator"
+
+#: google-authenticator.php:176
+msgid "<strong>ERROR</strong>: The Google Authenticator password is incorrect."
+msgstr "<strong>ERROR</strong>: El codigo es incorrecto."
+
+#: google-authenticator.php:179
+msgid ""
+"<strong>ERROR</strong>: The Google Authenticator code is incorrect or has "
+"expired."
+msgstr "<strong>ERROR</strong>: El código es incorrecto o caducado."
+
+#: google-authenticator.php:215
+msgid "WordPress Blog"
+msgstr "Blog de WordPress"
+
+#: google-authenticator.php:218 google-authenticator.php:392
+msgid "Google Authenticator Settings"
+msgstr "Opciones Google Authenticator"
+
+#: google-authenticator.php:223 google-authenticator.php:396
+msgid "Active"
+msgstr "Activar"
+
+#: google-authenticator.php:235
+msgid "Relaxed mode"
+msgstr "Modo relajado"
+
+#: google-authenticator.php:237
+msgid ""
+" Relaxed mode allows for more time drifting on your phone clock (&#177;4 "
+"min)."
+msgstr ""
+"El modo relajado permite tener más tiempo de reloj en su teléfono (&#177;4 "
+"min)."
+
+#: google-authenticator.php:242
+msgid "Description"
+msgstr "Descripción"
+
+#: google-authenticator.php:243
+msgid ""
+" Description that you'll see in the Google Authenticator app on your phone."
+msgstr ""
+"Descripción que se verá en la aplicación Google Authenticator en su teléfono."
+
+#: google-authenticator.php:247
+msgid "Secret"
+msgstr "Secreto"
+
+#: google-authenticator.php:250
+msgid "Create new secret"
+msgstr "Crear nueva clave secreta"
+
+#: google-authenticator.php:251
+msgid "Show/Hide QR code"
+msgstr "Mostar/Esconder QR Code"
+
+#: google-authenticator.php:259
+msgid "Scan this with the Google Authenticator app."
+msgstr "Escanear esto con la aplicación Google Authenticator."
+
+#: google-authenticator.php:264
+msgid "Enable App password"
+msgstr "Permitir contraseña de aplicación"
+
+#: google-authenticator.php:266
+msgid " Enabling an App password will decrease your overall login security."
+msgstr "Permitir una contraseña de aplicación disminuirá su seguridad global."
+
+#: google-authenticator.php:274
+msgid "Create new password"
+msgstr "Crear nueva contraseña"
+
+#: google-authenticator.php:275
+msgid ""
+" Password is not stored in cleartext, this is your only chance to see it."
+msgstr ""
+"La contraseña no está almacenada en formato de texto, es su única "
+"oportunidad de verla."
+
+#. Plugin Name of the plugin/theme
+msgid "Google Authenticator"
+msgstr ""
+
+#. Plugin URI of the plugin/theme
+msgid "http://henrik.schack.dk/google-authenticator-for-wordpress"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid ""
+"Two-Factor Authentication for WordPress using the Android/iPhone/Blackberry "
+"app as One Time Password generator."
+msgstr ""
+"La autentificación en dos pasos por wordpress utiliza una app Android/iPhone/"
+"Blackberry como 'One Time Password generator.'"
+
+#. Author of the plugin/theme
+msgid "Henrik Schack"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "http://henrik.schack.dk/"
+msgstr ""
diff --git a/plugins/google-authenticator/lang/google-authenticator-fr_FR.mo b/plugins/google-authenticator/lang/google-authenticator-fr_FR.mo
new file mode 100644
index 00000000..000ac747
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-fr_FR.mo
Binary files differ
diff --git a/plugins/google-authenticator/lang/google-authenticator-fr_FR.po b/plugins/google-authenticator/lang/google-authenticator-fr_FR.po
new file mode 100644
index 00000000..9dcbd951
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-fr_FR.po
@@ -0,0 +1,133 @@
+# Copyright (C) 2010 Google Authenticator
+# This file is distributed under the same license as the Google Authenticator package.
+msgid ""
+msgstr ""
+"Project-Id-Version: Google Authenticator 0.37\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/google-authenticator\n"
+"POT-Creation-Date: 2011-08-21 14:25:45+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2014-01-11 10:15+0100\n"
+"Last-Translator: \n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"X-Generator: Poedit 1.6.3\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"Language: fr_FR\n"
+
+#: google-authenticator.php:131
+msgid ""
+"If you don't have Google Authenticator enabled for your WordPress account, "
+"leave this field empty."
+msgstr ""
+"Si vous n'avez pas activé Google ASuthenticator pour votre compte wordpress, "
+"laissez ce champ vide."
+
+#: google-authenticator.php:131
+msgid "Google Authenticator code"
+msgstr "Code Google Authenticator"
+
+#: google-authenticator.php:176
+msgid "<strong>ERROR</strong>: The Google Authenticator password is incorrect."
+msgstr "<strong>ERREUR</strong>: Le code Google Authenticator est incorrect."
+
+#: google-authenticator.php:179
+msgid ""
+"<strong>ERROR</strong>: The Google Authenticator code is incorrect or has "
+"expired."
+msgstr ""
+"<strong>ERREUR</strong>: Le code Google Authenticator est incorrect ou "
+"périmé."
+
+#: google-authenticator.php:215
+msgid "WordPress Blog"
+msgstr "Blog WordPress"
+
+#: google-authenticator.php:218 google-authenticator.php:392
+msgid "Google Authenticator Settings"
+msgstr "Réglages Google Authenticator"
+
+#: google-authenticator.php:223 google-authenticator.php:396
+msgid "Active"
+msgstr "Activer"
+
+#: google-authenticator.php:235
+msgid "Relaxed mode"
+msgstr "Mode relax"
+
+#: google-authenticator.php:237
+msgid ""
+" Relaxed mode allows for more time drifting on your phone clock (&#177;4 "
+"min)."
+msgstr ""
+"Le mode relax vous permet d'avoir plus de temps de latence sur le chrono de "
+"votre téléphone (&#177;4 min)."
+
+#: google-authenticator.php:242
+msgid "Description"
+msgstr "Description"
+
+#: google-authenticator.php:243
+msgid ""
+" Description that you'll see in the Google Authenticator app on your phone."
+msgstr ""
+"Voici la description que vous verrez dans l'app Gogogle Authentiator de "
+"votre téléphone."
+
+#: google-authenticator.php:247
+msgid "Secret"
+msgstr "Code secret"
+
+#: google-authenticator.php:250
+msgid "Create new secret"
+msgstr "Créer nouveau code secret"
+
+#: google-authenticator.php:251
+msgid "Show/Hide QR code"
+msgstr "Montrer/Cacher le QR Code"
+
+#: google-authenticator.php:259
+msgid "Scan this with the Google Authenticator app."
+msgstr "Scanner ceci avec votre app Google Authenticator"
+
+#: google-authenticator.php:264
+msgid "Enable App password"
+msgstr "Autoriser mot de passe de l'app"
+
+#: google-authenticator.php:266
+msgid " Enabling an App password will decrease your overall login security."
+msgstr ""
+"Autoriser un mot de passe d'app réduira votre sécurité globale de connexion."
+
+#: google-authenticator.php:274
+msgid "Create new password"
+msgstr "Créer nouveau mot de passe"
+
+#: google-authenticator.php:275
+msgid ""
+" Password is not stored in cleartext, this is your only chance to see it."
+msgstr ""
+"Le mot de passe n'est pas stocké en texte clair, c'est votre seule "
+"opportunité de le voir."
+
+#. Plugin Name of the plugin/theme
+msgid "Google Authenticator"
+msgstr "Google Authenticator"
+
+#. Plugin URI of the plugin/theme
+msgid "http://henrik.schack.dk/google-authenticator-for-wordpress"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid ""
+"Two-Factor Authentication for WordPress using the Android/iPhone/Blackberry "
+"app as One Time Password generator."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "Henrik Schack"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "http://henrik.schack.dk/"
+msgstr ""
diff --git a/plugins/google-authenticator/lang/google-authenticator-it_IT.mo b/plugins/google-authenticator/lang/google-authenticator-it_IT.mo
new file mode 100644
index 00000000..dae99aef
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-it_IT.mo
Binary files differ
diff --git a/plugins/google-authenticator/lang/google-authenticator-it_IT.po b/plugins/google-authenticator/lang/google-authenticator-it_IT.po
new file mode 100644
index 00000000..361d5810
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-it_IT.po
@@ -0,0 +1,143 @@
+# Copyright (C) 2010 Google Authenticator
+# This file is distributed under the same license as the Google Authenticator package.
+# Aldo Latino <aldolat@gmail.com>, 2012, 2014.
+msgid ""
+msgstr ""
+"Project-Id-Version: Google Authenticator 0.37\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/google-authenticator\n"
+"POT-Creation-Date: 2014-01-11 07:14:22+00:00\n"
+"PO-Revision-Date: 2014-01-12 21:24+0100\n"
+"Last-Translator: Aldo Latino <aldolat@gmail.com>\n"
+"Language-Team: Italian <kde-i18n-it@kde.org>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Lokalize 1.5\n"
+
+#: google-authenticator.php:166
+msgid ""
+"If you don't have Google Authenticator enabled for your WordPress account, "
+"leave this field empty."
+msgstr ""
+"Se Google Authenticator non è attivo per il tuo account WordPress, lascia "
+"vuoto questo campo."
+
+#: google-authenticator.php:166
+msgid "Google Authenticator code"
+msgstr "Codice di Google Authenticator"
+
+#: google-authenticator.php:231
+msgid "<strong>ERROR</strong>: The Google Authenticator password is incorrect."
+msgstr ""
+"<strong>ERRORE</strong>: la password di Google Authenticator non è corretta.."
+
+#: google-authenticator.php:234
+msgid ""
+"<strong>ERROR</strong>: The Google Authenticator code is incorrect or has "
+"expired."
+msgstr ""
+"<strong>ERRORE</strong>: Il codice di Google Authenticator non è corretto o "
+"è scaduto."
+
+#: google-authenticator.php:274
+msgid "WordPressBlog"
+msgstr "WordPress Blog"
+
+#: google-authenticator.php:277 google-authenticator.php:469
+msgid "Google Authenticator Settings"
+msgstr "Impostazioni di Google Authenticator"
+
+#: google-authenticator.php:282 google-authenticator.php:481
+msgid "Active"
+msgstr "Attivo"
+
+#: google-authenticator.php:290
+msgid "Relaxed mode"
+msgstr "Modalità comoda"
+
+#: google-authenticator.php:292
+msgid ""
+" Relaxed mode allows for more time drifting on your phone clock (&#177;4 "
+"min)."
+msgstr ""
+" La modalità comoda permette uno scostamento di tempo più esteso rispetto "
+"all'orologio del telefono (&#177;4 min)."
+
+#: google-authenticator.php:297
+msgid "Description"
+msgstr "Descrizione"
+
+#: google-authenticator.php:298
+msgid ""
+" Description that you'll see in the Google Authenticator app on your phone."
+msgstr ""
+" La descrizione che si vede nell'app Google Authenticator sul telefono."
+
+#: google-authenticator.php:302
+msgid "Secret"
+msgstr "Chiave segreta"
+
+#: google-authenticator.php:305
+msgid "Create new secret"
+msgstr "Crea una nuova chiave segreta"
+
+#: google-authenticator.php:306
+msgid "Show/Hide QR code"
+msgstr "Mostra/nascondi il codice QR"
+
+#: google-authenticator.php:315
+msgid "Scan this with the Google Authenticator app."
+msgstr "Effettua la scansione con l'app Google Authenticator."
+
+#: google-authenticator.php:320
+msgid "Enable App password"
+msgstr "Abilita la password delle App"
+
+#: google-authenticator.php:322
+msgid " Enabling an App password will decrease your overall login security."
+msgstr ""
+" L'abilitazione della password delle App abbasserà il livello di sicurezza "
+"generale del login."
+
+#: google-authenticator.php:330
+msgid "Create new password"
+msgstr "Crea una nuova password"
+
+#: google-authenticator.php:331
+msgid ""
+" Password is not stored in cleartext, this is your only chance to see it."
+msgstr ""
+" La password non è conservata in chiaro: questo l'unico momento in cui la si "
+"può vedere."
+
+#: google-authenticator.php:474
+msgid "Hide settings from user"
+msgstr "Nascondi le impostazioni agli utenti"
+
+#. Plugin Name of the plugin/theme
+msgid "Google Authenticator"
+msgstr "Google Authenticator"
+
+#. Plugin URI of the plugin/theme
+msgid "http://henrik.schack.dk/google-authenticator-for-wordpress"
+msgstr "http://henrik.schack.dk/google-authenticator-for-wordpress"
+
+#. Description of the plugin/theme
+msgid ""
+"Two-Factor Authentication for WordPress using the Android/iPhone/Blackberry "
+"app as One Time Password generator."
+msgstr ""
+"Autenticazione a due fattori per WordPress utilizzando un'app su Android/"
+"iPhone/Blackberry come generatore di Password usa-e-getta."
+
+#. Author of the plugin/theme
+msgid "Henrik Schack"
+msgstr "Henrik Schack"
+
+#. Author URI of the plugin/theme
+msgid "http://henrik.schack.dk/"
+msgstr "http://henrik.schack.dk/"
+
+
diff --git a/plugins/google-authenticator/lang/google-authenticator-zh_CN.mo b/plugins/google-authenticator/lang/google-authenticator-zh_CN.mo
new file mode 100644
index 00000000..cdf342ea
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-zh_CN.mo
Binary files differ
diff --git a/plugins/google-authenticator/lang/google-authenticator-zh_CN.po b/plugins/google-authenticator/lang/google-authenticator-zh_CN.po
new file mode 100644
index 00000000..8b6cb67e
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator-zh_CN.po
@@ -0,0 +1,126 @@
+# Copyright (C) 2010 Google Authenticator
+# This file is distributed under the same license as the Google Authenticator package.
+msgid ""
+msgstr ""
+"Project-Id-Version: Google Authenticator 0.37\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/google-authenticator\n"
+"POT-Creation-Date: 2014-01-11 07:14:22+00:00\n"
+"PO-Revision-Date: 2014-01-13 13:48+0800\n"
+"Last-Translator: Kaijia Feng <fengkaijia@gmail.com>\n"
+"Language-Team: \n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.5.5\n"
+
+#: google-authenticator.php:166
+msgid ""
+"If you don't have Google Authenticator enabled for your WordPress account, "
+"leave this field empty."
+msgstr "如果您的帐号没有启用Google Authenticator身份验证功能,请不必填写此栏。"
+
+#: google-authenticator.php:166
+msgid "Google Authenticator code"
+msgstr "Google Authenticator验证码"
+
+#: google-authenticator.php:231
+msgid "<strong>ERROR</strong>: The Google Authenticator password is incorrect."
+msgstr "<strong>错误</strong>:Google Authenticator验证码有误。"
+
+#: google-authenticator.php:234
+msgid ""
+"<strong>ERROR</strong>: The Google Authenticator code is incorrect or has "
+"expired."
+msgstr "<strong>错误</strong>:Google Authenticator验证码有误或者已经失效。"
+
+#: google-authenticator.php:274
+msgid "WordPressBlog"
+msgstr "WordPressBlog"
+
+#: google-authenticator.php:277 google-authenticator.php:469
+msgid "Google Authenticator Settings"
+msgstr "Google Authenticator设置"
+
+#: google-authenticator.php:282 google-authenticator.php:481
+msgid "Active"
+msgstr "启用"
+
+#: google-authenticator.php:290
+msgid "Relaxed mode"
+msgstr "宽松模式"
+
+#: google-authenticator.php:292
+msgid ""
+" Relaxed mode allows for more time drifting on your phone clock (&#177;4 "
+"min)."
+msgstr " 在宽松模式下你可以有更长的时间输入验证码(&#177;4分钟)。"
+
+#: google-authenticator.php:297
+msgid "Description"
+msgstr "描述"
+
+#: google-authenticator.php:298
+msgid ""
+" Description that you'll see in the Google Authenticator app on your phone."
+msgstr " 在Google Authenticator应用中显示的帐户描述。"
+
+#: google-authenticator.php:302
+msgid "Secret"
+msgstr "密钥"
+
+#: google-authenticator.php:305
+msgid "Create new secret"
+msgstr "创建新密钥"
+
+#: google-authenticator.php:306
+msgid "Show/Hide QR code"
+msgstr "显示/隐藏QR码"
+
+#: google-authenticator.php:315
+msgid "Scan this with the Google Authenticator app."
+msgstr "使用Google Authenticator应用扫描此图像。"
+
+#: google-authenticator.php:320
+msgid "Enable App password"
+msgstr "启用应用专用密码"
+
+#: google-authenticator.php:322
+msgid " Enabling an App password will decrease your overall login security."
+msgstr " 启用应用专用密码将会在总体上降低登录的安全性。"
+
+#: google-authenticator.php:330
+msgid "Create new password"
+msgstr "创建新密码"
+
+#: google-authenticator.php:331
+msgid ""
+" Password is not stored in cleartext, this is your only chance to see it."
+msgstr " 密码将不会明文储存,这将是你唯一一次看见密码。"
+
+#: google-authenticator.php:474
+msgid "Hide settings from user"
+msgstr "不对用户显示设置"
+
+#. Plugin Name of the plugin/theme
+msgid "Google Authenticator"
+msgstr "Google Authenticator"
+
+#. Plugin URI of the plugin/theme
+msgid "http://henrik.schack.dk/google-authenticator-for-wordpress"
+msgstr "http://henrik.schack.dk/google-authenticator-for-wordpress"
+
+#. Description of the plugin/theme
+msgid ""
+"Two-Factor Authentication for WordPress using the Android/iPhone/Blackberry "
+"app as One Time Password generator."
+msgstr ""
+"使用Android/iPhone/Blackberry一次性密码生成应用为WordPress提供两步验证。"
+
+#. Author of the plugin/theme
+msgid "Henrik Schack"
+msgstr "Henrik Schack"
+
+#. Author URI of the plugin/theme
+msgid "http://henrik.schack.dk/"
+msgstr "http://henrik.schack.dk/"
diff --git a/plugins/google-authenticator/lang/google-authenticator.pot b/plugins/google-authenticator/lang/google-authenticator.pot
new file mode 100644
index 00000000..c14d5c1b
--- /dev/null
+++ b/plugins/google-authenticator/lang/google-authenticator.pot
@@ -0,0 +1,112 @@
+# Copyright (C) 2014 Google Authenticator
+# This file is distributed under the same license as the Google Authenticator package.
+msgid ""
+msgstr ""
+"Project-Id-Version: Google Authenticator 0.47\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/google-authenticator\n"
+"POT-Creation-Date: 2014-01-11 07:14:22+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2014-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+
+#: google-authenticator.php:166
+msgid "If you don't have Google Authenticator enabled for your WordPress account, leave this field empty."
+msgstr ""
+
+#: google-authenticator.php:166
+msgid "Google Authenticator code"
+msgstr ""
+
+#: google-authenticator.php:231
+msgid "<strong>ERROR</strong>: The Google Authenticator password is incorrect."
+msgstr ""
+
+#: google-authenticator.php:234
+msgid "<strong>ERROR</strong>: The Google Authenticator code is incorrect or has expired."
+msgstr ""
+
+#: google-authenticator.php:274
+msgid "WordPressBlog"
+msgstr ""
+
+#: google-authenticator.php:277 google-authenticator.php:469
+msgid "Google Authenticator Settings"
+msgstr ""
+
+#: google-authenticator.php:282 google-authenticator.php:481
+msgid "Active"
+msgstr ""
+
+#: google-authenticator.php:290
+msgid "Relaxed mode"
+msgstr ""
+
+#: google-authenticator.php:292
+msgid " Relaxed mode allows for more time drifting on your phone clock (&#177;4 min)."
+msgstr ""
+
+#: google-authenticator.php:297
+msgid "Description"
+msgstr ""
+
+#: google-authenticator.php:298
+msgid " Description that you'll see in the Google Authenticator app on your phone."
+msgstr ""
+
+#: google-authenticator.php:302
+msgid "Secret"
+msgstr ""
+
+#: google-authenticator.php:305
+msgid "Create new secret"
+msgstr ""
+
+#: google-authenticator.php:306
+msgid "Show/Hide QR code"
+msgstr ""
+
+#: google-authenticator.php:315
+msgid "Scan this with the Google Authenticator app."
+msgstr ""
+
+#: google-authenticator.php:320
+msgid "Enable App password"
+msgstr ""
+
+#: google-authenticator.php:322
+msgid " Enabling an App password will decrease your overall login security."
+msgstr ""
+
+#: google-authenticator.php:330
+msgid "Create new password"
+msgstr ""
+
+#: google-authenticator.php:331
+msgid " Password is not stored in cleartext, this is your only chance to see it."
+msgstr ""
+
+#: google-authenticator.php:474
+msgid "Hide settings from user"
+msgstr ""
+#. Plugin Name of the plugin/theme
+msgid "Google Authenticator"
+msgstr ""
+
+#. Plugin URI of the plugin/theme
+msgid "http://henrik.schack.dk/google-authenticator-for-wordpress"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid "Two-Factor Authentication for WordPress using the Android/iPhone/Blackberry app as One Time Password generator."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "Henrik Schack"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "http://henrik.schack.dk/"
+msgstr ""
diff --git a/plugins/google-authenticator/readme.txt b/plugins/google-authenticator/readme.txt
new file mode 100644
index 00000000..865d784e
--- /dev/null
+++ b/plugins/google-authenticator/readme.txt
@@ -0,0 +1,170 @@
+=== Google Authenticator ===
+Contributors: Henrik.Schack
+Donate Link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=henrik%40schack%2edk&lc=US&item_name=Google%20Authenticator&item_number=Google%20Authenticator&no_shipping=0&no_note=1&tax=0&bn=PP%2dDonationsBF&charset=UTF%2d8
+Tags: authentication,otp,password,security,login,android,iphone,blackberry
+Requires at least: 4.5
+Tested up to: 4.7
+Stable tag: 0.48
+
+Google Authenticator for your WordPress blog.
+
+== Description ==
+
+The Google Authenticator plugin for WordPress gives you two-factor authentication using the Google Authenticator app for Android/iPhone/Blackberry.
+
+If you are security aware, you may already have the Google Authenticator app installed on your smartphone, using it for two-factor authentication on Gmail/Dropbox/Lastpass/Amazon etc.
+
+The two-factor authentication requirement can be enabled on a per-user basis. You could enable it for your administrator account, but log in as usual with less privileged accounts.
+
+If You need to maintain your blog using an Android/iPhone app, or any other software using the XMLRPC interface, you can enable the App password feature in this plugin,
+but please note that enabling the App password feature will make your blog less secure.
+
+== Installation ==
+1. Make sure your webhost is capable of providing accurate time information for PHP/WordPress, ie. make sure a NTP daemon is running on the server.
+2. Install and activate the plugin.
+3. Enter a description on the Users -> Profile and Personal options page, in the Google Authenticator section.
+4. Scan the generated QR code with your phone, or enter the secret manually, remember to pick the time based one.
+You may also want to write down the secret on a piece of paper and store it in a safe place.
+5. Remember to hit the **Update profile** button at the bottom of the page before leaving the Personal options page.
+6. That's it, your WordPress blog is now a little more secure.
+
+== Frequently Asked Questions ==
+
+= Can I use Google Authenticator for WordPress with the Android/iPhone apps for WordPress? =
+
+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.
+
+= I want to update the secret, should I just scan the new QR code after creating a new secret? =
+
+No, you'll have to delete the existing account from the Google Authenticator app on your smartphone before you scan the new QR code, that is unless you change the description as well.
+
+= I am unable to log in using this plugin, what's wrong ? =
+
+The Google Authenticator verification codes are time based, so it's crucial that the clock in your phone is accurate and in sync with the clock on the server where your WordPress installation is hosted.
+If you have an Android phone, you can use an app like [ClockSync](https://market.android.com/details?id=ru.org.amip.ClockSync) to set your clock in case your Cell provider doesn't provide accurate time information
+Another option is to enable "relaxed mode" in the settings for the plugin, this will enable more valid codes by allowing up to a 4 min. timedrift in each direction.
+
+= I have several users on my WordPress installation, is that a supported configuration ? =
+
+Yes, each user has his own Google Authenticator settings.
+
+= During installation I forgot the thing about making sure my webhost is capable of providing accurate time information, I'm now unable to login, please help. =
+
+If you have SSH or FTP access to your webhosting account, you can manually delete the plugin from your WordPress installation,
+just delete the wp-content/plugins/google-authenticator directory, and you'll be able to login using username/password again.
+
+= I don't own a Smartphone, isn't there another way to generate these secret codes ? =
+
+Yes, there is a webbased version here : http://gauth.apps.gbraad.nl/
+Github project here : https://github.com/gbraad/html5-google-authenticator
+
+= Can I create backupcodes ? =
+
+No, but if you're using an Android smartphone you can replace the Google Authenticator app with [Authenticator Plus](https://play.google.com/store/apps/details?id=com.mufri.authenticatorplus).
+It's a really nice app that can import your existing settings, sync between devices and backup/restore using your sd-card.
+It's not a free app, but it's well worth the money.
+
+= Any known incompatabilities ? =
+
+Yes, the Man-in-the-middle attack/replay detection code isn't compatible with the test/setup mode in the "Stop spammer registration plugin",
+please remember to remove the "Check credentials on all login attempts" checkmark before installing my plugin.
+
+
+
+== Screenshots ==
+
+1. The enhanced log-in box.
+2. Google Authenticator section on the Profile and Personal options page.
+3. QR code on the Profile and Personal options page.
+4. Google Authenticator app on Android
+
+== Changelog ==
+= 0.48 =
+* Security fix / compatability with WordPress 4.5
+
+= 0.47 =
+* Google chart API replaced with jquery-qrcode
+* QR codes now contain a heading saying WordPress (Feature request by Flemming Mahler)
+* Danish translation & updated .pot file.
+* Plugin now logs login attempts recognized as Man-in-the-middle attacks.
+
+= 0.46 =
+* Man-in-the-middle attack protection added.
+* Show warning before displaying the QR code.
+* FAQ updated.
+
+= 0.45 =
+* Spaces in the description field should now work on iPhones.
+* Some depricated function calls replaced.
+* Code inputfield easier to use for .jp users now.
+* Sanitize description field input.
+* App password hash function switched to one that doesn't have rainbow tables available.
+* PHP notices occurring during app password login removed.
+
+
+= 0.44 =
+* Installation/FAQ section updated.
+* Simplified Chinese translation by Kaijia Feng added.
+* Tabindex on loginpage removed, no longer needed, was used by older WordPress installations.
+* Inputfield renamed to "googleotp".
+* Defaultdescription changed to "WordPressBlog" to avoid trouble for iPhone users.
+* Compatibility with Ryan Hellyer's plugin http://geek.ryanhellyer.net/products/deactivate-google-authenticator/
+* Must enter all 6 code digits.
+
+= 0.43 =
+* It's now possible for an admin to hide the Google Authenticaator settings on a per-user basis. (Feature request by : Skate-O)
+
+= 0.42 =
+* Autocomplete disabled on code input field. (Feature request by : hiphopsmurf)
+
+= 0.41 =
+* Italian translation by Aldo Latino added.
+
+= 0.40 =
+* Bugfix, typo corrected and PHP notices removed. Thanks to Dion Hulse for his patch.
+
+= 0.39 =
+* Bugfix, Description was not saved to WordPress database when updating profile. Thanks to xxdesmus for noticing this.
+
+= 0.38 =
+* Usability fix, input field for codes changed from password to text type.
+
+= 0.37 =
+* The plugin now supports "relaxed mode" when authenticating. If selected, codes from 4 minutes before and 4 minutes after will work. 30 seconds before and after is still the default setting.
+
+= 0.36 =
+* Bugfix, now an App password can only be used for XMLRPC/APP-Request logins.
+
+= 0.35 =
+* Initial WordPress app support added (XMLRPC).
+
+= 0.30 =
+* Code cleanup
+* Changed generation of secret key, to no longer have requirement of SHA256 on the server
+* German translation
+
+= 0.20 =
+* Initial release
+
+
+== Credits ==
+
+Thanks to:
+
+[Tobias Bäthge](http://tobias.baethge.com/) for his code rewrite and German translation.
+
+[Pascal de Bruijn](http://blog.pcode.nl/) for his "relaxed mode" idea.
+
+[Daniel Werl](http://technobabbl.es/) for his usability tips.
+
+[Dion Hulse](http://dd32.id.au/) for his bugfixes.
+
+[Aldo Latino](http://profiles.wordpress.org/users/aldolat/) for his Italian translation.
+
+[Kaijia Feng](http://www.kaijia.me/) for his Simplified Chinese translation.
+
+[Alex Concha](http://www.buayacorp.com/) for his security tips.
+
+[Jerome Etienne](http://jetienne.com/) for his jquery-qrcode plugin.
+
+[Sébastien Prunier](http://orizhial.com/) for his Spanish and French translation.
diff --git a/plugins/google-authenticator/screenshot-1.jpg b/plugins/google-authenticator/screenshot-1.jpg
new file mode 100644
index 00000000..252831f3
--- /dev/null
+++ b/plugins/google-authenticator/screenshot-1.jpg
Binary files differ
diff --git a/plugins/google-authenticator/screenshot-2.jpg b/plugins/google-authenticator/screenshot-2.jpg
new file mode 100644
index 00000000..13bb25c2
--- /dev/null
+++ b/plugins/google-authenticator/screenshot-2.jpg
Binary files differ
diff --git a/plugins/google-authenticator/screenshot-3.jpg b/plugins/google-authenticator/screenshot-3.jpg
new file mode 100644
index 00000000..b74aeae5
--- /dev/null
+++ b/plugins/google-authenticator/screenshot-3.jpg
Binary files differ
diff --git a/plugins/google-authenticator/screenshot-4.jpg b/plugins/google-authenticator/screenshot-4.jpg
new file mode 100644
index 00000000..804f3cad
--- /dev/null
+++ b/plugins/google-authenticator/screenshot-4.jpg
Binary files differ
diff --git a/plugins/google-authenticator/screenshot-5.jpg b/plugins/google-authenticator/screenshot-5.jpg
new file mode 100644
index 00000000..1b396294
--- /dev/null
+++ b/plugins/google-authenticator/screenshot-5.jpg
Binary files differ