| 1 |
<?php |
| 2 |
/* |
| 3 |
Plugin Name: Two Factor Authentication |
| 4 |
Plugin URI: |
| 5 |
Description: Secure your WordPress login forms with two factor authentication - including WooCommerce login forms |
| 6 |
Author: David Nutbourne + David Anderson, original plugin by Oskar Hane |
| 7 |
Author URI: https://www.simbahosting.co.uk |
| 8 |
Version: 1.0 |
| 9 |
License: GPLv2 or later |
| 10 |
*/ |
| 11 |
|
| 12 |
define('SIMBA_TFA_TEXT_DOMAIN', 'two-factor-authentication'); |
| 13 |
define('SIMBA_TFA_PLUGIN_DIR', dirname( __FILE__ )); |
| 14 |
define('SIMBA_TFA_PLUGIN_URL', plugins_url('', __FILE__)); |
| 15 |
|
| 16 |
class Simba_Two_Factor_Authentication { |
| 17 |
|
| 18 |
public $version = '1.0'; |
| 19 |
private $php_required = '5.3'; |
| 20 |
|
| 21 |
public function __construct() { |
| 22 |
|
| 23 |
if (file_exists(SIMBA_TFA_PLUGIN_DIR.'/premium.php')) include_once(SIMBA_TFA_PLUGIN_DIR.'/premium.php'); |
| 24 |
|
| 25 |
if (version_compare(PHP_VERSION, $this->php_required, '<' )) { |
| 26 |
add_action('all_admin_notices', array($this, 'admin_notice_insufficient_php')); |
| 27 |
$abort = true; |
| 28 |
} |
| 29 |
|
| 30 |
if (!function_exists('mcrypt_get_iv_size')) { |
| 31 |
add_action('all_admin_notices', array($this, 'admin_notice_missing_mcrypt')); |
| 32 |
$abort = true; |
| 33 |
} |
| 34 |
|
| 35 |
if (!empty($abort)) return; |
| 36 |
|
| 37 |
add_action('wp_ajax_nopriv_simbatfa-init-otp', array($this, 'tfaInitLogin')); |
| 38 |
|
| 39 |
add_action('wp_ajax_simbatfa_shared_ajax', array($this, 'shared_ajax')); |
| 40 |
|
| 41 |
add_action('woocommerce_before_customer_login_form', array($this, 'woocommerce_before_customer_login_form')); |
| 42 |
|
| 43 |
if (is_admin()) { |
| 44 |
//Save settings |
| 45 |
add_action('admin_init', array($this, 'check_possible_reset')); |
| 46 |
|
| 47 |
//Add to Settings menu |
| 48 |
add_action('admin_menu', array($this, 'addTwoFactorAuthAdminMenu')); |
| 49 |
|
| 50 |
//Add settings link in plugin list |
| 51 |
$plugin = plugin_basename(__FILE__); |
| 52 |
add_filter("plugin_action_links_".$plugin, array($this, 'addPluginSettingsLink' )); |
| 53 |
|
| 54 |
} else { |
| 55 |
add_action('init', array($this, 'check_possible_reset')); |
| 56 |
} |
| 57 |
|
| 58 |
add_action('plugins_loaded', array($this, 'plugins_loaded')); |
| 59 |
|
| 60 |
//Show off sync message for hotp |
| 61 |
add_action('admin_notices', array($this, 'tfaShowHOTPOffSyncMessage')); |
| 62 |
add_action('login_enqueue_scripts', array($this, 'login_enqueue_scripts')); |
| 63 |
add_action('admin_menu', array($this, 'admin_menu')); |
| 64 |
|
| 65 |
add_filter('authenticate', array($this, 'tfaVerifyCodeAndUser'), 99999999999, 3); |
| 66 |
} |
| 67 |
|
| 68 |
public function admin_notice_insufficient_php() { |
| 69 |
$this->show_admin_warning('<strong>'.__('Higher PHP version required', 'updraftplus').'</strong><br> '.sprintf(__('The Two Factor Authentication plugin requires PHP version %s or higher - your current version is only %s.', SIMBA_TFA_TEXT_DOMAIN), $this->php_required, PHP_VERSION), 'error'); |
| 70 |
} |
| 71 |
|
| 72 |
public function admin_notice_missing_mcrypt() { |
| 73 |
$this->show_admin_warning('<strong>'.__('PHP Mcrypt module required', 'updraftplus').'</strong><br> '.__('The Two Factor Authentication plugin requires the PHP mcrypt module to be installed. Please ask your web hosting company to install it.', SIMBA_TFA_TEXT_DOMAIN), 'error'); |
| 74 |
} |
| 75 |
|
| 76 |
private function show_admin_warning($message, $class = "updated") { |
| 77 |
echo '<div class="updraftmessage '.$class.'">'."<p>$message</p></div>"; |
| 78 |
} |
| 79 |
|
| 80 |
public function getTFA() |
| 81 |
{ |
| 82 |
if (!class_exists('HOTP')) require_once(SIMBA_TFA_PLUGIN_DIR.'/hotp-php-master/hotp.php'); |
| 83 |
if (!class_exists('Base32')) require_once(SIMBA_TFA_PLUGIN_DIR.'/Base32/Base32.php'); |
| 84 |
if (!class_exists('Simba_TFA')) require_once(SIMBA_TFA_PLUGIN_DIR.'/includes/class.TFA.php'); |
| 85 |
|
| 86 |
$tfa = new Simba_TFA(new Base32(), new HOTP()); |
| 87 |
|
| 88 |
return $tfa; |
| 89 |
} |
| 90 |
|
| 91 |
// "Shared" - i.e. could be called from either front-end or back-end |
| 92 |
public function shared_ajax() { |
| 93 |
if (empty($_POST['subaction']) || empty($_POST['nonce']) || !is_user_logged_in() || !wp_verify_nonce($_POST['nonce'], 'tfa_shared_nonce')) die('Security check.'); |
| 94 |
|
| 95 |
if ($_POST['subaction'] == 'refreshotp') { |
| 96 |
|
| 97 |
global $current_user; |
| 98 |
|
| 99 |
$tfa_priv_key_64 = get_user_meta($current_user->ID, 'tfa_priv_key_64', true); |
| 100 |
|
| 101 |
if (!$tfa_priv_key_64) { |
| 102 |
echo json_encode(array('code' => '')); |
| 103 |
die; |
| 104 |
} |
| 105 |
|
| 106 |
echo json_encode(array('code' => $this->getTFA()->generateOTP($current_user->ID, $tfa_priv_key_64))); |
| 107 |
exit; |
| 108 |
} |
| 109 |
|
| 110 |
} |
| 111 |
|
| 112 |
public function tfaInitLogin() { |
| 113 |
|
| 114 |
if (empty($_POST['user']) || empty($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'simba_tfa_loginform_nonce')) die('Security check.'); |
| 115 |
|
| 116 |
$tfa = $this->getTFA(); |
| 117 |
$res = $tfa->preAuth(array('log' => $_POST['user'])); |
| 118 |
|
| 119 |
echo json_encode(array('status' => $res)); |
| 120 |
exit; |
| 121 |
} |
| 122 |
|
| 123 |
|
| 124 |
// Here's where the login action happens |
| 125 |
public function tfaVerifyCodeAndUser($user, $username, $password) |
| 126 |
{ |
| 127 |
|
| 128 |
$tfa = $this->getTFA(); |
| 129 |
|
| 130 |
if (is_wp_error($user)) return $user; |
| 131 |
|
| 132 |
$params = $_POST; |
| 133 |
$params['log'] = $username; |
| 134 |
$params['caller'] = $_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['REQUEST_URI']; |
| 135 |
|
| 136 |
$code_ok = $tfa->authUserFromLogin($params); |
| 137 |
|
| 138 |
if(!$code_ok) |
| 139 |
return new WP_Error('authentication_failed', '<strong>'.__('Error:', SIMBA_TFA_TEXT_DOMAIN).'</strong> '.__('The one-time password (TFA code) you entered was incorrect.', SIMBA_TFA_TEXT_DOMAIN)); |
| 140 |
|
| 141 |
if($user) |
| 142 |
return $user; |
| 143 |
|
| 144 |
return wp_authenticate_username_password(null, $username, $password); |
| 145 |
} |
| 146 |
|
| 147 |
public function tfaRegisterTwoFactorAuthSettings() |
| 148 |
{ |
| 149 |
global $wp_roles; |
| 150 |
if (!isset($wp_roles)) |
| 151 |
$wp_roles = new WP_Roles(); |
| 152 |
|
| 153 |
foreach($wp_roles->role_names as $id => $name) |
| 154 |
{ |
| 155 |
register_setting('tfa_user_roles_group', 'tfa_'.$id); |
| 156 |
} |
| 157 |
|
| 158 |
register_setting('simba_tfa_default_hmac_group', 'tfa_default_hmac'); |
| 159 |
register_setting('tfa_xmlrpc_status_group', 'tfa_xmlrpc_on'); |
| 160 |
} |
| 161 |
|
| 162 |
public function tfaListEnableRadios($user_id, $long_label = false) |
| 163 |
{ |
| 164 |
if(!$user_id) |
| 165 |
return; |
| 166 |
|
| 167 |
$setting = get_user_meta($user_id, 'tfa_enable_tfa', true); |
| 168 |
$setting = !$setting ? false : $setting; |
| 169 |
|
| 170 |
$tfa_enabled_label = ($long_label) ? __('Enable two-factor authentication', SIMBA_TFA_TEXT_DOMAIN) : __('Enabled', SIMBA_TFA_TEXT_DOMAIN); |
| 171 |
$tfa_disabled_label = ($long_label) ? __('Disable two-factor authentication', SIMBA_TFA_TEXT_DOMAIN) : __('Disabled', SIMBA_TFA_TEXT_DOMAIN); |
| 172 |
|
| 173 |
print '<input type="radio" id="tfa_enable_tfa_true" name="tfa_enable_tfa" value="true" '.($setting == true ? 'checked="checked"' :'').'> <label for="tfa_enable_tfa_true">'.apply_filters('simbatfa_radiolabel_enabled', $tfa_enabled_label, $long_label).'</label> <br>'; |
| 174 |
print '<input type="radio" id="tfa_enable_tfa_false" name="tfa_enable_tfa" value="false" '.($setting == false ? 'checked="checked"' :'').'> <label for="tfa_enable_tfa_false">'.apply_filters('simbatfa_radiolabel_disabled', $tfa_disabled_label, $long_label).'</label> <br>'; |
| 175 |
} |
| 176 |
|
| 177 |
|
| 178 |
public function tfaListAlgorithmRadios($user_id) |
| 179 |
{ |
| 180 |
if(!$user_id) return; |
| 181 |
|
| 182 |
$types = array('totp' => __('TOTP (time based - most common algorithm; used by Google Authenticator)', SIMBA_TFA_TEXT_DOMAIN), 'hotp' => __('HOTP (event based)', SIMBA_TFA_TEXT_DOMAIN)); |
| 183 |
|
| 184 |
$setting = get_user_meta($user_id, 'tfa_algorithm_type', true); |
| 185 |
$setting = $setting === false || !$setting ? 'totp' : $setting; |
| 186 |
|
| 187 |
foreach($types as $id => $name) { |
| 188 |
print '<input type="radio" id="tfa_algorithm_type_'.esc_attr($id).'" name="tfa_algorithm_type" value="'.$id.'" '.($setting == $id ? 'checked="checked"' :'').'> <label for="tfa_algorithm_type_'.esc_attr($id).'">'.$name."</label><br>\n"; |
| 189 |
} |
| 190 |
} |
| 191 |
|
| 192 |
public function tfaListUserRolesCheckboxes() |
| 193 |
{ |
| 194 |
global $wp_roles; |
| 195 |
if (!isset($wp_roles)) $wp_roles = new WP_Roles(); |
| 196 |
|
| 197 |
foreach($wp_roles->role_names as $id => $name) |
| 198 |
{ |
| 199 |
$setting = get_option('tfa_'.$id); |
| 200 |
$setting = $setting === false || $setting ? 1 : 0; |
| 201 |
|
| 202 |
print '<input type="checkbox" id="tfa_'.$id.'" name="tfa_'.$id.'" value="1" '.($setting ? 'checked="checked"' :'').'> <label for="tfa_'.$id.'">'.htmlspecialchars($name)."</label><br>\n"; |
| 203 |
} |
| 204 |
|
| 205 |
} |
| 206 |
|
| 207 |
public function tfaListDefaultHMACRadios() |
| 208 |
{ |
| 209 |
$tfa = $this->getTFA(); |
| 210 |
$setting = get_option('tfa_default_hmac'); |
| 211 |
$setting = $setting === false || !$setting ? $tfa->default_hmac : $setting; |
| 212 |
|
| 213 |
$types = array('totp' => __('TOTP (time based - most common algorithm; used by Google Authenticator)', SIMBA_TFA_TEXT_DOMAIN), 'hotp' => __('HOTP (event based)', SIMBA_TFA_TEXT_DOMAIN)); |
| 214 |
|
| 215 |
foreach($types as $id => $name) |
| 216 |
print '<input type="radio" id="tfa_default_hmac_'.esc_attr($id).'" name="tfa_default_hmac" value="'.$id.'" '.($setting == $id ? 'checked="checked"' :'').'> '.'<label for="tfa_default_hmac_'.esc_attr($id).'">'."$name</label><br>\n"; |
| 217 |
} |
| 218 |
|
| 219 |
|
| 220 |
public function tfaListXMLRPCStatusRadios() |
| 221 |
{ |
| 222 |
$tfa = $this->getTFA(); |
| 223 |
$setting = get_option('tfa_xmlrpc_on'); |
| 224 |
$setting = $setting === false || !$setting ? 0 : 1; |
| 225 |
|
| 226 |
$types = array('0' => __('OFF', SIMBA_TFA_TEXT_DOMAIN), '1' => __('ON', SIMBA_TFA_TEXT_DOMAIN)); |
| 227 |
|
| 228 |
foreach($types as $id => $name) |
| 229 |
print '<input type="radio" name="tfa_xmlrpc_on" value="'.$id.'" '.($setting == $id ? 'checked="checked"' :'').'> - '.$name."<br>\n"; |
| 230 |
} |
| 231 |
|
| 232 |
|
| 233 |
public function tfaShowAdminSettingsPage() |
| 234 |
{ |
| 235 |
$tfa = $this->getTFA(); |
| 236 |
require_once(SIMBA_TFA_PLUGIN_DIR.'/includes/admin_settings.php'); |
| 237 |
} |
| 238 |
|
| 239 |
public function tfaShowUserSettingsPage() |
| 240 |
{ |
| 241 |
$tfa = $this->getTFA(); |
| 242 |
include SIMBA_TFA_PLUGIN_DIR.'/includes/user_settings.php'; |
| 243 |
} |
| 244 |
|
| 245 |
|
| 246 |
public function admin_menu() |
| 247 |
{ |
| 248 |
$tfa = $this->getTFA(); |
| 249 |
|
| 250 |
global $current_user; |
| 251 |
if(!$tfa->isActivatedForUser($current_user->ID)) return; |
| 252 |
|
| 253 |
add_menu_page(__('Two Factor Authentication', SIMBA_TFA_TEXT_DOMAIN), __('Two Factor Auth', SIMBA_TFA_TEXT_DOMAIN), 'read', 'two-factor-auth-user', array($this, 'tfaShowUserSettingsPage'), SIMBA_TFA_PLUGIN_URL.'/img/tfa_admin_icon_16x16.png', 72); |
| 254 |
} |
| 255 |
|
| 256 |
public function addTwoFactorAuthAdminMenu() |
| 257 |
{ |
| 258 |
add_action( 'admin_init', array($this, 'tfaRegisterTwoFactorAuthSettings' )); |
| 259 |
add_options_page('Two Factor Authentication', 'Two Factor Authentication', 'manage_options', 'two-factor-auth', array($this, 'tfaShowAdminSettingsPage')); |
| 260 |
} |
| 261 |
|
| 262 |
public function addPluginSettingsLink($links) |
| 263 |
{ |
| 264 |
|
| 265 |
$link = '<a href="options-general.php?page=two-factor-auth">'.__('Plugin settings', SIMBA_TFA_TEXT_DOMAIN).'</a>'; |
| 266 |
array_unshift($links, $link); |
| 267 |
|
| 268 |
$link2 = '<a href="admin.php?page=two-factor-auth-user">'.__('User settings', SIMBA_TFA_TEXT_DOMAIN).'</a>'; |
| 269 |
array_unshift($links, $link2); |
| 270 |
|
| 271 |
return $links; |
| 272 |
} |
| 273 |
|
| 274 |
public function check_possible_reset() { |
| 275 |
if(!empty($_GET['simbatfa_priv_key_reset']) && !empty($_REQUEST['nonce']) && wp_verify_nonce($_REQUEST['nonce'], 'simbatfa_reset_private_key')) |
| 276 |
{ |
| 277 |
$this->reset_private_key_and_emergency_codes(); |
| 278 |
// if (empty($_REQUEST['noredirect'])) exit; |
| 279 |
exit; |
| 280 |
} |
| 281 |
|
| 282 |
} |
| 283 |
|
| 284 |
public function reset_private_key_and_emergency_codes() { |
| 285 |
global $current_user; |
| 286 |
delete_user_meta($current_user->ID, 'tfa_priv_key_64'); |
| 287 |
delete_user_meta($current_user->ID, 'simba_tfa_emergency_codes_64'); |
| 288 |
if (empty($_REQUEST['noredirect'])) { |
| 289 |
wp_safe_redirect( admin_url('admin.php').'?page=two-factor-auth-user&settings-updated=1'); |
| 290 |
} else { |
| 291 |
$url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . remove_query_arg(array('simbatfa_priv_key_reset', 'noredirect', 'nonce')); |
| 292 |
|
| 293 |
wp_redirect($url); |
| 294 |
} |
| 295 |
} |
| 296 |
|
| 297 |
public function reset_link($admin = true) { |
| 298 |
|
| 299 |
$url_base = ($admin) ? admin_url('admin.php').'?page=two-factor-auth-user&settings-updated=1' : (( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST']); |
| 300 |
|
| 301 |
$add_query_args = array( |
| 302 |
'simbatfa_priv_key_reset' => 1, |
| 303 |
); |
| 304 |
if (!$admin) $add_query_args['noredirect'] = 1; |
| 305 |
|
| 306 |
$url = $url_base.add_query_arg($add_query_args); |
| 307 |
|
| 308 |
$url = wp_nonce_url($url, 'simbatfa_reset_private_key', 'nonce'); |
| 309 |
|
| 310 |
return '<a href="javascript:if(confirm(\''.__('Warning: if you reset this key you will have to update your apps with the new one. Are you sure you want this?', SIMBA_TFA_TEXT_DOMAIN).'\')){ window.location = \''.esc_js($url).'\'; }">'.__('Reset private key', SIMBA_TFA_TEXT_DOMAIN).'</a>'; |
| 311 |
|
| 312 |
} |
| 313 |
|
| 314 |
public function footer() { |
| 315 |
?> |
| 316 |
<script> |
| 317 |
jQuery(document).ready(function($) { |
| 318 |
$('.simbaotp_refresh').click(function(e) { |
| 319 |
e.preventDefault(); |
| 320 |
$(".simba_current_otp").html('<em><?php echo esc_attr(__('Updating...', SIMBA_TFA_TEXT_DOMAIN));?></em>'); |
| 321 |
$.post('<?php echo esc_js(admin_url('admin-ajax.php'));?>', { |
| 322 |
action: "simbatfa_shared_ajax", |
| 323 |
subaction: "refreshotp", |
| 324 |
nonce: "<?php echo esc_js(wp_create_nonce("tfa_shared_nonce"));?>" |
| 325 |
}, function(response) { |
| 326 |
try { |
| 327 |
var resp = $.parseJSON(response); |
| 328 |
$(".simba_current_otp").html(resp.code); |
| 329 |
} catch(err) { |
| 330 |
alert("<?php echo esc_js(__('Response:', 'SIMBA_TFA_TEXT_DOMAIN')); ?> "+response); |
| 331 |
console.log(response); |
| 332 |
console.log(err); |
| 333 |
} |
| 334 |
}); |
| 335 |
}); |
| 336 |
}); |
| 337 |
</script> |
| 338 |
<?php |
| 339 |
} |
| 340 |
|
| 341 |
public function current_codes_box($admin = true) { |
| 342 |
|
| 343 |
global $current_user; |
| 344 |
$tfa = $this->getTFA(); |
| 345 |
|
| 346 |
static $added_footer; |
| 347 |
if (empty($added_footer)) { |
| 348 |
$added_footer = true; |
| 349 |
wp_enqueue_script('jquery'); |
| 350 |
add_action( $admin ? 'admin_footer' : 'wp_footer' , array($this, 'footer')); |
| 351 |
} |
| 352 |
|
| 353 |
$url = preg_replace('/^https?:\/\//', '', site_url()); |
| 354 |
|
| 355 |
$tfa_priv_key_64 = get_user_meta($current_user->ID, 'tfa_priv_key_64', true); |
| 356 |
|
| 357 |
if(!$tfa_priv_key_64) $tfa_priv_key_64 = $tfa->addPrivateKey($current_user->ID); |
| 358 |
|
| 359 |
$tfa_priv_key = trim($tfa->getPrivateKeyPlain($tfa_priv_key_64, $current_user->ID)); |
| 360 |
|
| 361 |
$tfa_priv_key_32 = Base32::encode($tfa_priv_key); |
| 362 |
|
| 363 |
$algorithm_type = $tfa->getUserAlgorithm($current_user->ID); |
| 364 |
|
| 365 |
|
| 366 |
if ($admin) { |
| 367 |
echo '<h2>'.__('Current codes', SIMBA_TFA_TEXT_DOMAIN).'</h2>'; |
| 368 |
} else { |
| 369 |
// echo '<h2>'.__('Current one-time password', SIMBA_TFA_TEXT_DOMAIN).' '.$this->reset_current_otp_link().'</h2>'; |
| 370 |
} |
| 371 |
|
| 372 |
?> |
| 373 |
<div class="postbox"> |
| 374 |
|
| 375 |
<?php if ($admin) { ?> |
| 376 |
<h3 style="padding: 10px 6px 0px; margin:4px 0 0; cursor: default;"> |
| 377 |
<span style="cursor: default;"><?php echo __('Current one-time password', SIMBA_TFA_TEXT_DOMAIN).' '.$this->reset_current_otp_link(); ?> </span> |
| 378 |
<div class="inside"> |
| 379 |
<p><strong style="font-size: 3em;"><span class="simba_current_otp"><?php print $tfa->generateOTP($current_user->ID, $tfa_priv_key_64); ?></span></strong></p> |
| 380 |
</div> |
| 381 |
</h3> |
| 382 |
<?php } else { |
| 383 |
?> |
| 384 |
<div class="inside"> |
| 385 |
<p class="simbatfa-frontend-current-otp" style="font-size: 1.5em; margin-top:6px;"> |
| 386 |
<strong> |
| 387 |
<?php echo __('Current one-time password', SIMBA_TFA_TEXT_DOMAIN).' '.$this->reset_current_otp_link(); ?> |
| 388 |
</strong> : |
| 389 |
|
| 390 |
<span class="simba_current_otp"><?php print $tfa->generateOTP($current_user->ID, $tfa_priv_key_64); ?></span> |
| 391 |
|
| 392 |
</p> |
| 393 |
</div> |
| 394 |
|
| 395 |
<?php } ?> |
| 396 |
|
| 397 |
<?php if ($admin) { ?> |
| 398 |
<h3 style="padding-left: 10px; cursor: default;"> |
| 399 |
<span style="cursor: default;"><?php _e('QR code', SIMBA_TFA_TEXT_DOMAIN); ?></span> |
| 400 |
</h3> |
| 401 |
<?php } else { |
| 402 |
echo '<h2>'.__('QR code', SIMBA_TFA_TEXT_DOMAIN).'</h2>'; |
| 403 |
} ?> |
| 404 |
<div class="inside"> |
| 405 |
<p> |
| 406 |
<?php _e('Scan this code with Duo Mobile, Google Authenticator or any other app that supports 6 digit OTPs', SIMBA_TFA_TEXT_DOMAIN); ?>. |
| 407 |
|
| 408 |
<?php _e('You are currently using', SIMBA_TFA_TEXT_DOMAIN); ?> <?php print strtoupper($algorithm_type).', '.($algorithm_type == 'totp' ? __('a time based', SIMBA_TFA_TEXT_DOMAIN) : __('an event based', SIMBA_TFA_TEXT_DOMAIN)); ?> <?php _e('algorithm', SIMBA_TFA_TEXT_DOMAIN); ?>. |
| 409 |
</p> |
| 410 |
<p title="<?php echo sprintf(__("Private key: %s (base 32: %s)", SIMBA_TFA_TEXT_DOMAIN), $tfa_priv_key, $tfa_priv_key_32);?>"> |
| 411 |
<?php echo $this->tfa_qr_code_url($algorithm_type, $url, $tfa_priv_key) ?> |
| 412 |
</p> |
| 413 |
</div> |
| 414 |
|
| 415 |
<div class="inside"> |
| 416 |
|
| 417 |
<h3 class="normal" style="cursor: default"><?php _e('Private key - always to be kept secret', SIMBA_TFA_TEXT_DOMAIN); ?></h3> |
| 418 |
|
| 419 |
<p> |
| 420 |
<strong><?php echo __('Private key (base 32 - used by Google Authenticator and Authy):', SIMBA_TFA_TEXT_DOMAIN);?></strong> |
| 421 |
<?php echo htmlspecialchars($tfa_priv_key_32); ?><br> |
| 422 |
|
| 423 |
<strong><?php echo __('Private key:', SIMBA_TFA_TEXT_DOMAIN);?></strong> |
| 424 |
<?php echo htmlspecialchars($tfa_priv_key); ?><br> |
| 425 |
|
| 426 |
<?php echo $this->reset_link($admin); ?> |
| 427 |
</p> |
| 428 |
</div> |
| 429 |
|
| 430 |
<?php |
| 431 |
if ($admin || apply_filters('simba_tfa_emergency_codes_user_settings', false) !== false) { |
| 432 |
?> |
| 433 |
<div class="inside"> |
| 434 |
|
| 435 |
<h3 class="normal" style="cursor: default"><?php _e('Emergency codes', SIMBA_TFA_TEXT_DOMAIN); ?></h3> |
| 436 |
|
| 437 |
<p> |
| 438 |
<?php |
| 439 |
$default_text = __('One-time emergency codes are a feature of the Premium version of this plugin.', SIMBA_TFA_TEXT_DOMAIN); |
| 440 |
echo apply_filters('simba_tfa_emergency_codes_user_settings', $default_text); |
| 441 |
?> |
| 442 |
</p> |
| 443 |
|
| 444 |
</div> |
| 445 |
|
| 446 |
<?php } ?> |
| 447 |
|
| 448 |
</div> |
| 449 |
<?php |
| 450 |
} |
| 451 |
|
| 452 |
public function reset_current_otp_link($admin = true) { |
| 453 |
return '<a href="#" class="simbaotp_refresh">'.__('(update)', SIMBA_TFA_TEXT_DOMAIN).'</a>'; |
| 454 |
} |
| 455 |
|
| 456 |
public function advanced_settings_box($submit_button_callback = false) { |
| 457 |
$tfa = $this->getTFA(); |
| 458 |
|
| 459 |
global $current_user; |
| 460 |
$algorithm_type = $tfa->getUserAlgorithm($current_user->ID); |
| 461 |
|
| 462 |
?> |
| 463 |
<h2><?php _e('Advanced settings', SIMBA_TFA_TEXT_DOMAIN); ?></h2> |
| 464 |
|
| 465 |
<div id="tfa_advanced_box" class="tfa_settings_form" style="margin-top: 20px;"> |
| 466 |
|
| 467 |
<?php if (false === $submit_button_callback) { ?><form method="post" action="<?php print add_query_arg('settings-updated', 'true', $_SERVER['REQUEST_URI']); ?>"><?php } ?> |
| 468 |
|
| 469 |
<?php _e('Choose which algorithm for One Time Passwords you want to use.', SIMBA_TFA_TEXT_DOMAIN); ?> |
| 470 |
<p> |
| 471 |
<?php |
| 472 |
$this->tfaListAlgorithmRadios($current_user->ID); |
| 473 |
if($algorithm_type == 'hotp') |
| 474 |
{ |
| 475 |
$counter = $tfa->getUserCounter($current_user->ID); |
| 476 |
print '<br>'.__('Your counter on the server is currently on', SIMBA_TFA_TEXT_DOMAIN).': '.$counter; |
| 477 |
} |
| 478 |
?> |
| 479 |
|
| 480 |
</p> |
| 481 |
<?php if (false === $submit_button_callback) { submit_button(); echo '</form>'; } else { call_user_func($submit_button_callback); } ?> |
| 482 |
</div> |
| 483 |
<?php |
| 484 |
} |
| 485 |
|
| 486 |
public function login_enqueue_scripts() |
| 487 |
{ |
| 488 |
|
| 489 |
if(isset($_GET['action']) && $_GET['action'] != 'logout' && $_GET['action'] != 'login') return; |
| 490 |
|
| 491 |
// Prevent cacheing when in debug mode |
| 492 |
$script_ver = (defined('WP_DEBUG') && WP_DEBUG) ? time() : $wp_version; |
| 493 |
|
| 494 |
wp_enqueue_script( 'tfa-ajax-request', SIMBA_TFA_PLUGIN_URL . '/includes/tfa.js', array( 'jquery' ), $script_ver ); |
| 495 |
wp_localize_script( 'tfa-ajax-request', 'simba_tfasettings', array( |
| 496 |
'ajaxurl' => admin_url('admin-ajax.php'), |
| 497 |
'click_to_enter_otp' => __("Click to enter One Time Password", SIMBA_TFA_TEXT_DOMAIN), |
| 498 |
'enter_username_first' => __('You have to enter a username first.', SIMBA_TFA_TEXT_DOMAIN), |
| 499 |
'otp' => __("One Time Password (i.e. 2FA)", SIMBA_TFA_TEXT_DOMAIN), |
| 500 |
'otp_login_help' => __('(check your OTP app to get this password)', SIMBA_TFA_TEXT_DOMAIN), |
| 501 |
'nonce' => wp_create_nonce("simba_tfa_loginform_nonce") |
| 502 |
)); |
| 503 |
} |
| 504 |
|
| 505 |
public function tfaShowHOTPOffSyncMessage() |
| 506 |
{ |
| 507 |
global $current_user; |
| 508 |
$is_off_sync = get_user_meta($current_user->ID, 'tfa_hotp_off_sync', true); |
| 509 |
if(!$is_off_sync) |
| 510 |
return; |
| 511 |
|
| 512 |
?> |
| 513 |
<div class="error"> |
| 514 |
<h3><?php _e('Two Factor Authentication re-sync needed', SIMBA_TFA_TEXT_DOMAIN);?></h3> |
| 515 |
<p> |
| 516 |
You need to resync your mobile app for <strong>Two Factor Authentication</strong> since the OTP you last used is many steps ahead |
| 517 |
of the server. |
| 518 |
<br> |
| 519 |
<?php _e('Please re-sync or you might not be able to log in if you generate more OTPs without logging in.', SIMBA_TFA_TEXT_DOMAIN);?> |
| 520 |
<br><br> |
| 521 |
<a href="admin.php?page=two-factor-auth-user&warning_button_clicked=1" class="button">Click here and re-scan the QR-Code</a> |
| 522 |
</p> |
| 523 |
</div> |
| 524 |
|
| 525 |
<?php |
| 526 |
|
| 527 |
} |
| 528 |
|
| 529 |
// QR code image |
| 530 |
public function tfa_qr_code_url($algorithm_type, $url, $tfa_priv_key){ |
| 531 |
global $current_user; |
| 532 |
$tfa = $this->getTFA(); |
| 533 |
|
| 534 |
$ret = '<img src="https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://'.$algorithm_type.'/'.$url.':%2520'.$current_user->user_login.'%3Fsecret%3D'.Base32::encode($tfa_priv_key).'%26issuer='.$url.'%26counter='.$tfa->getUserCounter($current_user->ID).'">'; |
| 535 |
return $ret; |
| 536 |
} |
| 537 |
|
| 538 |
public function settings_intro_notices() { |
| 539 |
?> |
| 540 |
<p class="simba_tfa_personal_settings_notice simba_tfa_intro_notice"> |
| 541 |
<?php echo __('These are your personal settings.', SIMBA_TFA_TEXT_DOMAIN).' '.__('Nothing you change here will have any effect on other users.', SIMBA_TFA_TEXT_DOMAIN); ?> |
| 542 |
</p> |
| 543 |
<p class="simba_tfa_verify_tfa_notice simba_tfa_intro_notice"><strong> |
| 544 |
<?php _e('If you activate two-factor authentication, then verify with the One Time Password shown on this page before you log out.', SIMBA_TFA_TEXT_DOMAIN); ?></strong> |
| 545 |
</p> |
| 546 |
<?php |
| 547 |
} |
| 548 |
|
| 549 |
public function plugins_loaded() |
| 550 |
{ |
| 551 |
load_plugin_textdomain( |
| 552 |
SIMBA_TFA_TEXT_DOMAIN, |
| 553 |
false, |
| 554 |
dirname( plugin_basename( __FILE__ ) ) . '/languages/' |
| 555 |
); |
| 556 |
|
| 557 |
if ((!is_admin() || (defined('DOING_AJAX') && DOING_AJAX)) && is_user_logged_in() && file_exists(SIMBA_TFA_PLUGIN_DIR.'/includes/tfa_frontend.php')) { |
| 558 |
if (!class_exists('TFA_Frontend')) require_once(SIMBA_TFA_PLUGIN_DIR.'/includes/tfa_frontend.php'); |
| 559 |
new TFA_Frontend($this); |
| 560 |
} else { |
| 561 |
add_shortcode('twofactor_user_settings', array($this, 'shortcode_when_not_logged_in')); |
| 562 |
} |
| 563 |
|
| 564 |
} |
| 565 |
|
| 566 |
public function shortcode_when_not_logged_in() { |
| 567 |
return ''; |
| 568 |
} |
| 569 |
|
| 570 |
// WooCommerce login form |
| 571 |
public function woocommerce_before_customer_login_form() { |
| 572 |
wp_enqueue_script( 'tfa-wc-ajax-request', SIMBA_TFA_PLUGIN_URL.'/includes/wooextend.js', array('jquery')); |
| 573 |
wp_localize_script( 'tfa-wc-ajax-request', 'simbatfa_wc_settings', array( |
| 574 |
'ajaxurl' => admin_url('admin-ajax.php'), |
| 575 |
'click_to_enter_otp' => __("Enter One Time Password (if you have one)", SIMBA_TFA_TEXT_DOMAIN), |
| 576 |
'enter_username_first' => __('You have to enter a username first.', SIMBA_TFA_TEXT_DOMAIN), |
| 577 |
'otp' => __("One Time Password", SIMBA_TFA_TEXT_DOMAIN), |
| 578 |
'nonce' => wp_create_nonce("simba_tfa_loginform_nonce") |
| 579 |
)); |
| 580 |
} |
| 581 |
|
| 582 |
} |
| 583 |
|
| 584 |
$simba_two_factor_authentication = new Simba_Two_Factor_Authentication(); |