| 1 |
<?php |
| 2 |
/* |
| 3 |
Plugin Name: Two Factor Authentication |
| 4 |
Plugin URI: https://www.simbahosting.co.uk/s3/product/two-factor-authentication/ |
| 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.2.6 |
| 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.2.6'; |
| 19 |
private $php_required = '5.3'; |
| 20 |
|
| 21 |
private $frontend; |
| 22 |
|
| 23 |
public function __construct() { |
| 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 |
if (file_exists(SIMBA_TFA_PLUGIN_DIR.'/premium.php')) include_once(SIMBA_TFA_PLUGIN_DIR.'/premium.php'); |
| 38 |
|
| 39 |
add_action('wp_ajax_nopriv_simbatfa-init-otp', array($this, 'tfaInitLogin')); |
| 40 |
|
| 41 |
add_action('wp_ajax_simbatfa_shared_ajax', array($this, 'shared_ajax')); |
| 42 |
|
| 43 |
add_action('woocommerce_before_customer_login_form', array($this, 'woocommerce_before_customer_login_form')); |
| 44 |
// The login form on the checkout doesn't call the woocommerce_before_customer_login_form action |
| 45 |
add_action('woocommerce_before_checkout_form', array($this, 'woocommerce_before_customer_login_form')); |
| 46 |
|
| 47 |
if (is_admin()) { |
| 48 |
//Save settings |
| 49 |
add_action('admin_init', array($this, 'check_possible_reset')); |
| 50 |
|
| 51 |
//Add to Settings menu on sites |
| 52 |
add_action('admin_menu', array($this, 'menu_entry_for_admin')); |
| 53 |
|
| 54 |
//Add settings link in plugin list |
| 55 |
$plugin = plugin_basename(__FILE__); |
| 56 |
add_filter("plugin_action_links_".$plugin, array($this, 'addPluginSettingsLink' )); |
| 57 |
add_filter('network_admin_plugin_action_links_'.$plugin, array($this, 'addPluginSettingsLink' )); |
| 58 |
|
| 59 |
// Entry that everybody gets |
| 60 |
add_action('network_admin_menu', array($this, 'admin_menu')); |
| 61 |
add_action('admin_menu', array($this, 'admin_menu')); |
| 62 |
|
| 63 |
} else { |
| 64 |
add_action('init', array($this, 'check_possible_reset')); |
| 65 |
} |
| 66 |
|
| 67 |
add_action('plugins_loaded', array($this, 'plugins_loaded')); |
| 68 |
add_action('init', array($this, 'init')); |
| 69 |
|
| 70 |
//Show off sync message for hotp |
| 71 |
add_action('admin_notices', array($this, 'tfaShowHOTPOffSyncMessage')); |
| 72 |
add_action('login_enqueue_scripts', array($this, 'login_enqueue_scripts')); |
| 73 |
|
| 74 |
if (!defined('TWO_FACTOR_DISABLE') || !TWO_FACTOR_DISABLE) { |
| 75 |
add_filter('authenticate', array($this, 'tfaVerifyCodeAndUser'), 99999999999, 3); |
| 76 |
} |
| 77 |
|
| 78 |
if (file_exists(SIMBA_TFA_PLUGIN_DIR.'/updater/updater.php')) include_once(SIMBA_TFA_PLUGIN_DIR.'/updater/updater.php'); |
| 79 |
|
| 80 |
if (defined('DOING_AJAX') && DOING_AJAX && defined('WP_ADMIN') && WP_ADMIN && !empty($_REQUEST['action']) && 'simbatfa-init-otp' == $_REQUEST['action']) { |
| 81 |
// Try to prevent PHP notices breaking the AJAX conversation |
| 82 |
$this->output_buffering = true; |
| 83 |
$this->logged = array(); |
| 84 |
set_error_handler(array($this, 'get_php_errors'), E_ALL & ~E_STRICT); |
| 85 |
ob_start(); |
| 86 |
} |
| 87 |
|
| 88 |
} |
| 89 |
|
| 90 |
public function get_php_errors($errno, $errstr, $errfile, $errline) { |
| 91 |
if (0 == error_reporting()) return true; |
| 92 |
$logline = $this->php_error_to_logline($errno, $errstr, $errfile, $errline); |
| 93 |
$this->logged[] = $logline; |
| 94 |
# Don't pass it up the chain (since it's going to be output to the user always) |
| 95 |
return true; |
| 96 |
} |
| 97 |
|
| 98 |
public function php_error_to_logline($errno, $errstr, $errfile, $errline) { |
| 99 |
switch ($errno) { |
| 100 |
case 1: $e_type = 'E_ERROR'; break; |
| 101 |
case 2: $e_type = 'E_WARNING'; break; |
| 102 |
case 4: $e_type = 'E_PARSE'; break; |
| 103 |
case 8: $e_type = 'E_NOTICE'; break; |
| 104 |
case 16: $e_type = 'E_CORE_ERROR'; break; |
| 105 |
case 32: $e_type = 'E_CORE_WARNING'; break; |
| 106 |
case 64: $e_type = 'E_COMPILE_ERROR'; break; |
| 107 |
case 128: $e_type = 'E_COMPILE_WARNING'; break; |
| 108 |
case 256: $e_type = 'E_USER_ERROR'; break; |
| 109 |
case 512: $e_type = 'E_USER_WARNING'; break; |
| 110 |
case 1024: $e_type = 'E_USER_NOTICE'; break; |
| 111 |
case 2048: $e_type = 'E_STRICT'; break; |
| 112 |
case 4096: $e_type = 'E_RECOVERABLE_ERROR'; break; |
| 113 |
case 8192: $e_type = 'E_DEPRECATED'; break; |
| 114 |
case 16384: $e_type = 'E_USER_DEPRECATED'; break; |
| 115 |
case 30719: $e_type = 'E_ALL'; break; |
| 116 |
default: $e_type = "E_UNKNOWN ($errno)"; break; |
| 117 |
} |
| 118 |
|
| 119 |
if (!is_string($errstr)) $errstr = serialize($errstr); |
| 120 |
|
| 121 |
if (0 === strpos($errfile, ABSPATH)) $errfile = substr($errfile, strlen(ABSPATH)); |
| 122 |
|
| 123 |
return "PHP event: code $e_type: $errstr (line $errline, $errfile)"; |
| 124 |
|
| 125 |
} |
| 126 |
|
| 127 |
public function init() { |
| 128 |
if ((!is_admin() || (defined('DOING_AJAX') && DOING_AJAX)) && is_user_logged_in() && file_exists(SIMBA_TFA_PLUGIN_DIR.'/includes/tfa_frontend.php')) { |
| 129 |
$this->load_frontend(); |
| 130 |
} else { |
| 131 |
add_shortcode('twofactor_user_settings', array($this, 'shortcode_when_not_logged_in')); |
| 132 |
} |
| 133 |
} |
| 134 |
|
| 135 |
public function admin_notice_insufficient_php() { |
| 136 |
$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'); |
| 137 |
} |
| 138 |
|
| 139 |
public function admin_notice_missing_mcrypt() { |
| 140 |
$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'); |
| 141 |
} |
| 142 |
|
| 143 |
public function show_admin_warning($message, $class = "updated") { |
| 144 |
echo '<div class="tfamessage '.$class.'">'."<p>$message</p></div>"; |
| 145 |
} |
| 146 |
|
| 147 |
public function getTFA() { |
| 148 |
if (!class_exists('HOTP')) require_once(SIMBA_TFA_PLUGIN_DIR.'/hotp-php-master/hotp.php'); |
| 149 |
if (!class_exists('Base32')) require_once(SIMBA_TFA_PLUGIN_DIR.'/Base32/Base32.php'); |
| 150 |
if (!class_exists('Simba_TFA')) require_once(SIMBA_TFA_PLUGIN_DIR.'/includes/class.TFA.php'); |
| 151 |
|
| 152 |
$tfa = new Simba_TFA(new Base32(), new HOTP()); |
| 153 |
|
| 154 |
return $tfa; |
| 155 |
} |
| 156 |
|
| 157 |
// "Shared" - i.e. could be called from either front-end or back-end |
| 158 |
public function shared_ajax() { |
| 159 |
if (empty($_POST['subaction']) || empty($_POST['nonce']) || !is_user_logged_in() || !wp_verify_nonce($_POST['nonce'], 'tfa_shared_nonce')) die('Security check (3).'); |
| 160 |
|
| 161 |
if ($_POST['subaction'] == 'refreshotp') { |
| 162 |
|
| 163 |
global $current_user; |
| 164 |
|
| 165 |
$tfa_priv_key_64 = get_user_meta($current_user->ID, 'tfa_priv_key_64', true); |
| 166 |
|
| 167 |
if (!$tfa_priv_key_64) { |
| 168 |
echo json_encode(array('code' => '')); |
| 169 |
die; |
| 170 |
} |
| 171 |
|
| 172 |
echo json_encode(array('code' => $this->getTFA()->generateOTP($current_user->ID, $tfa_priv_key_64))); |
| 173 |
exit; |
| 174 |
} |
| 175 |
|
| 176 |
} |
| 177 |
|
| 178 |
public function tfaInitLogin() { |
| 179 |
|
| 180 |
if (empty($_POST['user'])) die('Security check (2).'); |
| 181 |
|
| 182 |
if (defined('TWO_FACTOR_DISABLE') && TWO_FACTOR_DISABLE) { |
| 183 |
$res = false; |
| 184 |
} else { |
| 185 |
$tfa = $this->getTFA(); |
| 186 |
$res = $tfa->preAuth(array('log' => (string)$_POST['user'])); |
| 187 |
} |
| 188 |
|
| 189 |
$results = array('jsonstarter' => 'justhere', 'status' => $res); |
| 190 |
|
| 191 |
if (!empty($this->output_buffering)) { |
| 192 |
if (!empty($this->logged)) { |
| 193 |
$results['php_output'] = $this->logged; |
| 194 |
} |
| 195 |
restore_error_handler(); |
| 196 |
$buffered = ob_get_clean(); |
| 197 |
if ($buffered) $results['extra_output'] = $buffered; |
| 198 |
} |
| 199 |
|
| 200 |
echo json_encode($results); |
| 201 |
exit; |
| 202 |
} |
| 203 |
|
| 204 |
|
| 205 |
// Here's where the login action happens. Called on the 'authenticate' action. |
| 206 |
public function tfaVerifyCodeAndUser($user, $username, $password) { |
| 207 |
|
| 208 |
$tfa = $this->getTFA(); |
| 209 |
|
| 210 |
if (is_wp_error($user)) return $user; |
| 211 |
|
| 212 |
$params = $_POST; |
| 213 |
$params['log'] = $username; |
| 214 |
$params['caller'] = $_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['REQUEST_URI']; |
| 215 |
|
| 216 |
$code_ok = $tfa->authUserFromLogin($params); |
| 217 |
|
| 218 |
if (is_wp_error($code_ok)) return $code_ok; |
| 219 |
|
| 220 |
if (!$code_ok) 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)); |
| 221 |
|
| 222 |
if ($user) return $user; |
| 223 |
|
| 224 |
return wp_authenticate_username_password(null, $username, $password); |
| 225 |
} |
| 226 |
|
| 227 |
public function tfaRegisterTwoFactorAuthSettings() |
| 228 |
{ |
| 229 |
global $wp_roles; |
| 230 |
if (!isset($wp_roles)) |
| 231 |
$wp_roles = new WP_Roles(); |
| 232 |
|
| 233 |
foreach($wp_roles->role_names as $id => $name) |
| 234 |
{ |
| 235 |
register_setting('tfa_user_roles_group', 'tfa_'.$id); |
| 236 |
register_setting('tfa_user_roles_required_group', 'tfa_required_'.$id); |
| 237 |
} |
| 238 |
|
| 239 |
register_setting('tfa_user_roles_required_group', 'tfa_requireafter'); |
| 240 |
register_setting('simba_tfa_default_hmac_group', 'tfa_default_hmac'); |
| 241 |
register_setting('tfa_xmlrpc_status_group', 'tfa_xmlrpc_on'); |
| 242 |
} |
| 243 |
|
| 244 |
public function tfaListEnableRadios($user_id, $long_label = false) |
| 245 |
{ |
| 246 |
if(!$user_id) |
| 247 |
return; |
| 248 |
|
| 249 |
$setting = get_user_meta($user_id, 'tfa_enable_tfa', true); |
| 250 |
$setting = !$setting ? false : $setting; |
| 251 |
|
| 252 |
$tfa = $this->getTFA(); |
| 253 |
|
| 254 |
if ($tfa->isRequiredForUser($user_id)) { |
| 255 |
$requireafter = absint($this->get_option('tfa_requireafter')); |
| 256 |
|
| 257 |
echo '<p class="tfa_required_warning" style="font-weight:bold; font-style:italics;">'.sprintf(__('N.B. This site is configured to forbid you to log in if you disable two-factor authentication after your account is %d days old', SIMBA_TFA_TEXT_DOMAIN), $requireafter).'</p>'; |
| 258 |
} |
| 259 |
|
| 260 |
$tfa_enabled_label = ($long_label) ? __('Enable two-factor authentication', SIMBA_TFA_TEXT_DOMAIN) : __('Enabled', SIMBA_TFA_TEXT_DOMAIN); |
| 261 |
$tfa_disabled_label = ($long_label) ? __('Disable two-factor authentication', SIMBA_TFA_TEXT_DOMAIN) : __('Disabled', SIMBA_TFA_TEXT_DOMAIN); |
| 262 |
|
| 263 |
print '<input type="radio" class="tfa_enable_radio" id="tfa_enable_tfa_true" name="tfa_enable_tfa" value="true" '.($setting == true ? 'checked="checked"' :'').'> <label class="tfa_enable_radio_label" for="tfa_enable_tfa_true">'.apply_filters('simbatfa_radiolabel_enabled', $tfa_enabled_label, $long_label).'</label> <br>'; |
| 264 |
|
| 265 |
print '<input type="radio" class="tfa_enable_radio" id="tfa_enable_tfa_false" name="tfa_enable_tfa" value="false" '.($setting == false ? 'checked="checked"' :'').'> <label class="tfa_enable_radio_label" for="tfa_enable_tfa_false">'.apply_filters('simbatfa_radiolabel_disabled', $tfa_disabled_label, $long_label).'</label> <br>'; |
| 266 |
} |
| 267 |
|
| 268 |
|
| 269 |
public function tfaListAlgorithmRadios($user_id) |
| 270 |
{ |
| 271 |
if(!$user_id) return; |
| 272 |
|
| 273 |
$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)); |
| 274 |
|
| 275 |
$setting = get_user_meta($user_id, 'tfa_algorithm_type', true); |
| 276 |
$setting = $setting === false || !$setting ? 'totp' : $setting; |
| 277 |
|
| 278 |
foreach($types as $id => $name) { |
| 279 |
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"; |
| 280 |
} |
| 281 |
} |
| 282 |
|
| 283 |
public function get_option($key) { |
| 284 |
if (!is_multisite()) return get_option($key); |
| 285 |
switch_to_blog(1); |
| 286 |
$v = get_option($key); |
| 287 |
restore_current_blog(); |
| 288 |
return $v; |
| 289 |
} |
| 290 |
|
| 291 |
public function tfaListUserRolesCheckboxes() |
| 292 |
{ |
| 293 |
|
| 294 |
if (is_multisite()) { |
| 295 |
// Not a real WP role; needs separate handling |
| 296 |
$id = '_super_admin'; |
| 297 |
$name = __('Multisite Super Admin', SIMBA_TFA_TEXT_DOMAIN); |
| 298 |
$setting = $this->get_option('tfa_'.$id); |
| 299 |
$setting = $setting === false || $setting ? 1 : 0; |
| 300 |
|
| 301 |
print '<input type="checkbox" id="tfa_'.$id.'" name="tfa_'.$id.'" value="1" '.($setting ? 'checked="checked"' :'').'> <label for="tfa_'.$id.'">'.htmlspecialchars($name)."</label><br>\n"; |
| 302 |
} |
| 303 |
|
| 304 |
global $wp_roles; |
| 305 |
if (!isset($wp_roles)) $wp_roles = new WP_Roles(); |
| 306 |
|
| 307 |
foreach($wp_roles->role_names as $id => $name) |
| 308 |
{ |
| 309 |
$setting = $this->get_option('tfa_'.$id); |
| 310 |
$setting = $setting === false || $setting ? 1 : 0; |
| 311 |
|
| 312 |
print '<input type="checkbox" id="tfa_'.$id.'" name="tfa_'.$id.'" value="1" '.($setting ? 'checked="checked"' :'').'> <label for="tfa_'.$id.'">'.htmlspecialchars($name)."</label><br>\n"; |
| 313 |
} |
| 314 |
|
| 315 |
} |
| 316 |
|
| 317 |
public function tfaListDefaultHMACRadios() |
| 318 |
{ |
| 319 |
$tfa = $this->getTFA(); |
| 320 |
$setting = $this->get_option('tfa_default_hmac'); |
| 321 |
$setting = $setting === false || !$setting ? $tfa->default_hmac : $setting; |
| 322 |
|
| 323 |
$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)); |
| 324 |
|
| 325 |
foreach($types as $id => $name) |
| 326 |
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"; |
| 327 |
} |
| 328 |
|
| 329 |
public function tfaListXMLRPCStatusRadios() |
| 330 |
{ |
| 331 |
$tfa = $this->getTFA(); |
| 332 |
$setting = $this->get_option('tfa_xmlrpc_on'); |
| 333 |
$setting = $setting === false || !$setting ? 0 : 1; |
| 334 |
|
| 335 |
$types = array( |
| 336 |
'0' => __('Do not require 2FA over XMLRPC (best option if you must use XMLRPC and your client does not support 2FA)', SIMBA_TFA_TEXT_DOMAIN), |
| 337 |
'1' => __('Do require 2FA over XMLRPC (best option if you do not use XMLRPC or are unsure)', SIMBA_TFA_TEXT_DOMAIN) |
| 338 |
); |
| 339 |
|
| 340 |
foreach($types as $id => $name) |
| 341 |
print '<input type="radio" name="tfa_xmlrpc_on" id="tfa_xmlrpc_on_'.$id.'" value="'.$id.'" '.($setting == $id ? 'checked="checked"' :'').'> <label for="tfa_xmlrpc_on_'.$id.'">'.$name."</label><br>\n"; |
| 342 |
} |
| 343 |
|
| 344 |
public function tfaShowAdminSettingsPage() |
| 345 |
{ |
| 346 |
$tfa = $this->getTFA(); |
| 347 |
require_once(SIMBA_TFA_PLUGIN_DIR.'/includes/admin_settings.php'); |
| 348 |
} |
| 349 |
|
| 350 |
public function tfaShowUserSettingsPage() |
| 351 |
{ |
| 352 |
$tfa = $this->getTFA(); |
| 353 |
include SIMBA_TFA_PLUGIN_DIR.'/includes/user_settings.php'; |
| 354 |
} |
| 355 |
|
| 356 |
public function admin_menu() |
| 357 |
{ |
| 358 |
$tfa = $this->getTFA(); |
| 359 |
|
| 360 |
global $current_user; |
| 361 |
if(!$tfa->isActivatedForUser($current_user->ID)) return; |
| 362 |
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); |
| 363 |
} |
| 364 |
|
| 365 |
public function menu_entry_for_admin() { |
| 366 |
|
| 367 |
// On multisite, only show the entry on site ID 1 - to ensure options get saved in the right place. |
| 368 |
global $current_site, $wpdb; |
| 369 |
// $current_site is not the right way to do this - it is internal, and could be anything |
| 370 |
if (is_multisite() && (!is_super_admin() || !is_object($wpdb) || !isset($wpdb->blogid) || 1 != $wpdb->blogid)) return; |
| 371 |
|
| 372 |
add_action( 'admin_init', array($this, 'tfaRegisterTwoFactorAuthSettings' )); |
| 373 |
|
| 374 |
add_options_page( |
| 375 |
__('Two Factor Authentication', SIMBA_TFA_TEXT_DOMAIN), |
| 376 |
__('Two Factor Authentication', SIMBA_TFA_TEXT_DOMAIN), |
| 377 |
'manage_options', |
| 378 |
'two-factor-auth', |
| 379 |
array($this, 'tfaShowAdminSettingsPage') |
| 380 |
); |
| 381 |
} |
| 382 |
|
| 383 |
public function addPluginSettingsLink($links) |
| 384 |
{ |
| 385 |
if (!is_network_admin()) { |
| 386 |
$link = '<a href="options-general.php?page=two-factor-auth">'.__('Plugin settings', SIMBA_TFA_TEXT_DOMAIN).'</a>'; |
| 387 |
array_unshift($links, $link); |
| 388 |
} else { |
| 389 |
switch_to_blog(1); |
| 390 |
$link = '<a href="'.admin_url('options-general.php').'?page=two-factor-auth">'.__('Plugin settings', SIMBA_TFA_TEXT_DOMAIN).'</a>'; |
| 391 |
restore_current_blog(); |
| 392 |
array_unshift($links, $link); |
| 393 |
} |
| 394 |
|
| 395 |
$link2 = '<a href="admin.php?page=two-factor-auth-user">'.__('User settings', SIMBA_TFA_TEXT_DOMAIN).'</a>'; |
| 396 |
array_unshift($links, $link2); |
| 397 |
|
| 398 |
return $links; |
| 399 |
} |
| 400 |
|
| 401 |
public function check_possible_reset() { |
| 402 |
if(!empty($_GET['simbatfa_priv_key_reset']) && !empty($_REQUEST['nonce']) && wp_verify_nonce($_REQUEST['nonce'], 'simbatfa_reset_private_key')) |
| 403 |
{ |
| 404 |
$this->reset_private_key_and_emergency_codes(); |
| 405 |
// if (empty($_REQUEST['noredirect'])) exit; |
| 406 |
exit; |
| 407 |
} |
| 408 |
|
| 409 |
} |
| 410 |
|
| 411 |
public function reset_private_key_and_emergency_codes() { |
| 412 |
global $current_user; |
| 413 |
delete_user_meta($current_user->ID, 'tfa_priv_key_64'); |
| 414 |
delete_user_meta($current_user->ID, 'simba_tfa_emergency_codes_64'); |
| 415 |
if (empty($_REQUEST['noredirect'])) { |
| 416 |
wp_safe_redirect( admin_url('admin.php').'?page=two-factor-auth-user&settings-updated=1'); |
| 417 |
} else { |
| 418 |
$url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . remove_query_arg(array('simbatfa_priv_key_reset', 'noredirect', 'nonce')); |
| 419 |
|
| 420 |
wp_redirect(esc_url_raw($url)); |
| 421 |
} |
| 422 |
} |
| 423 |
|
| 424 |
public function reset_link($admin = true) { |
| 425 |
|
| 426 |
$url_base = ($admin) ? admin_url('admin.php').'?page=two-factor-auth-user&settings-updated=1' : (( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST']); |
| 427 |
|
| 428 |
$add_query_args = array( |
| 429 |
'simbatfa_priv_key_reset' => 1, |
| 430 |
); |
| 431 |
if (!$admin) $add_query_args['noredirect'] = 1; |
| 432 |
|
| 433 |
$url = $url_base.add_query_arg($add_query_args); |
| 434 |
|
| 435 |
$url = wp_nonce_url($url, 'simbatfa_reset_private_key', 'nonce'); |
| 436 |
|
| 437 |
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>'; |
| 438 |
|
| 439 |
} |
| 440 |
|
| 441 |
public function footer() { |
| 442 |
$ajax_url = admin_url('admin-ajax.php'); |
| 443 |
// It's possible that FORCE_ADMIN_SSL will make that SSL, whilst the user is on the front-end having logged in over non-SSL - and as a result, their login cookies won't get sent, and they're not registered as logged in. |
| 444 |
if (!is_admin() && substr(strtolower($ajax_url), 0, 6) == 'https:' && !is_ssl()) { |
| 445 |
$also_try = 'http:'.substr($ajax_url, 6); |
| 446 |
} |
| 447 |
?> |
| 448 |
<script> |
| 449 |
jQuery(document).ready(function($) { |
| 450 |
$('.simbaotp_qr_container').qrcode({ |
| 451 |
"render": "image", |
| 452 |
"text": $('.simbaotp_qr_container:first').data('qrcode'), |
| 453 |
}); |
| 454 |
$('.simbaotp_refresh').click(function(e) { |
| 455 |
e.preventDefault(); |
| 456 |
$(".simba_current_otp").html('<em><?php echo esc_attr(__('Updating...', SIMBA_TFA_TEXT_DOMAIN));?></em>'); |
| 457 |
$.post('<?php echo esc_js($ajax_url);?>', { |
| 458 |
action: "simbatfa_shared_ajax", |
| 459 |
subaction: "refreshotp", |
| 460 |
nonce: "<?php echo esc_js(wp_create_nonce("tfa_shared_nonce"));?>" |
| 461 |
}, function(response) { |
| 462 |
var got_code = ''; |
| 463 |
try { |
| 464 |
var resp = $.parseJSON(response); |
| 465 |
got_code = resp.code; |
| 466 |
} catch(err) { |
| 467 |
<?php if (!isset($also_try)) { ?> |
| 468 |
alert("<?php echo esc_js(__('Response:', 'SIMBA_TFA_TEXT_DOMAIN')); ?> "+response); |
| 469 |
<?php } ?> |
| 470 |
console.log(response); |
| 471 |
console.log(err); |
| 472 |
} |
| 473 |
<?php |
| 474 |
if (isset($also_try)) { |
| 475 |
?> |
| 476 |
$.post('<?php echo esc_js($also_try);?>', { |
| 477 |
action: "simbatfa_shared_ajax", |
| 478 |
subaction: "refreshotp", |
| 479 |
nonce: "<?php echo esc_js(wp_create_nonce("tfa_shared_nonce"));?>" |
| 480 |
}, function(response) { |
| 481 |
try { |
| 482 |
var resp = $.parseJSON(response); |
| 483 |
if (resp.code) { |
| 484 |
$(".simba_current_otp").html(resp.code); |
| 485 |
} else { |
| 486 |
console.log(response); |
| 487 |
console.log("TFA: no code found"); |
| 488 |
} |
| 489 |
} catch(err) { |
| 490 |
alert("<?php echo esc_js(__('Response:', 'SIMBA_TFA_TEXT_DOMAIN')); ?> "+response); |
| 491 |
console.log(response); |
| 492 |
console.log(err); |
| 493 |
} |
| 494 |
}); |
| 495 |
<?php } else { ?> |
| 496 |
if ('' != got_code) { |
| 497 |
$(".simba_current_otp").html(got_code); |
| 498 |
} else { |
| 499 |
console.log("TFA: no code found"); |
| 500 |
} |
| 501 |
<?php } ?> |
| 502 |
}); |
| 503 |
}); |
| 504 |
}); |
| 505 |
</script> |
| 506 |
<?php |
| 507 |
} |
| 508 |
|
| 509 |
public function print_private_keys($admin, $type = 'full', $user_id = false) { |
| 510 |
|
| 511 |
$tfa = $this->getTFA(); |
| 512 |
global $current_user; |
| 513 |
|
| 514 |
if ($user_id == false) $user_id = $current_user->ID; |
| 515 |
|
| 516 |
$tfa_priv_key_64 = get_user_meta($user_id, 'tfa_priv_key_64', true); |
| 517 |
if(!$tfa_priv_key_64) $tfa_priv_key_64 = $tfa->addPrivateKey($user_id); |
| 518 |
|
| 519 |
$tfa_priv_key = trim($tfa->getPrivateKeyPlain($tfa_priv_key_64, $user_id)); |
| 520 |
|
| 521 |
$tfa_priv_key_32 = Base32::encode($tfa_priv_key); |
| 522 |
|
| 523 |
if ('full' == $type) { |
| 524 |
?> |
| 525 |
<strong><?php echo __('Private key (base 32 - used by Google Authenticator and Authy):', SIMBA_TFA_TEXT_DOMAIN);?></strong> |
| 526 |
<?php echo htmlspecialchars($tfa_priv_key_32); ?><br> |
| 527 |
|
| 528 |
<strong><?php echo __('Private key:', SIMBA_TFA_TEXT_DOMAIN);?></strong> |
| 529 |
<?php echo htmlspecialchars($tfa_priv_key); ?><br> |
| 530 |
<?php |
| 531 |
} elseif ('plain' == $type) { |
| 532 |
echo htmlspecialchars($tfa_priv_key); |
| 533 |
} elseif ('base32' == $type) { |
| 534 |
echo htmlspecialchars($tfa_priv_key_32); |
| 535 |
} elseif ('base64' == $type) { |
| 536 |
echo htmlspecialchars($tfa_priv_key_64); |
| 537 |
} |
| 538 |
} |
| 539 |
|
| 540 |
public function current_otp_code($tfa, $user_id = false) { |
| 541 |
global $current_user; |
| 542 |
if (false == $user_id) $user_id = $current_user->ID; |
| 543 |
$tfa_priv_key_64 = get_user_meta($user_id, 'tfa_priv_key_64', true); |
| 544 |
return '<span class="simba_current_otp">'.$tfa->generateOTP($user_id, $tfa_priv_key_64).'</span>'; |
| 545 |
} |
| 546 |
|
| 547 |
public function add_footer($admin) { |
| 548 |
static $added_footer; |
| 549 |
if (empty($added_footer)) { |
| 550 |
$added_footer = true; |
| 551 |
// wp_enqueue_script('jquery'); |
| 552 |
$script_ver = (defined('WP_DEBUG') && WP_DEBUG) ? time() : $this->version; |
| 553 |
$script_file = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? 'jquery.qrcode.js' : 'jquery.qrcode.min.js'; |
| 554 |
wp_enqueue_script( 'jquery-qrcode', SIMBA_TFA_PLUGIN_URL.'/includes/jquery-qrcode/'.$script_file, array('jquery'), $script_ver); |
| 555 |
add_action( $admin ? 'admin_footer' : 'wp_footer' , array($this, 'footer')); |
| 556 |
} |
| 557 |
} |
| 558 |
|
| 559 |
public function current_codes_box($admin = true, $user_id = false) { |
| 560 |
|
| 561 |
global $current_user; |
| 562 |
|
| 563 |
if (false == $user_id) { |
| 564 |
$user_id = $current_user->ID; |
| 565 |
} |
| 566 |
|
| 567 |
$tfa = $this->getTFA(); |
| 568 |
|
| 569 |
$this->add_footer($admin); |
| 570 |
|
| 571 |
$url = preg_replace('/^https?:\/\//', '', site_url()); |
| 572 |
|
| 573 |
$tfa_priv_key_64 = get_user_meta($user_id, 'tfa_priv_key_64', true); |
| 574 |
|
| 575 |
if(!$tfa_priv_key_64) $tfa_priv_key_64 = $tfa->addPrivateKey($user_id); |
| 576 |
|
| 577 |
$tfa_priv_key = trim($tfa->getPrivateKeyPlain($tfa_priv_key_64, $user_id)); |
| 578 |
|
| 579 |
$tfa_priv_key_32 = Base32::encode($tfa_priv_key); |
| 580 |
|
| 581 |
$algorithm_type = $tfa->getUserAlgorithm($user_id); |
| 582 |
|
| 583 |
if ($admin) { |
| 584 |
if ($current_user->ID == $user_id) { |
| 585 |
echo '<h2>'.__('Current codes', SIMBA_TFA_TEXT_DOMAIN).'</h2>'; |
| 586 |
} else { |
| 587 |
$user = get_user_by('id', $user_id); |
| 588 |
$user_descrip = htmlspecialchars($user->user_nicename.' - '.$user->user_email); |
| 589 |
echo '<h2>'.sprintf(__('Current codes (login: %s)', SIMBA_TFA_TEXT_DOMAIN), $user_descrip).'</h2>'; |
| 590 |
} |
| 591 |
} else { |
| 592 |
// echo '<h2>'.__('Current one-time password', SIMBA_TFA_TEXT_DOMAIN).' '.$this->reset_current_otp_link().'</h2>'; |
| 593 |
} |
| 594 |
|
| 595 |
?> |
| 596 |
<div class="postbox"> |
| 597 |
|
| 598 |
<?php if ($admin) { ?> |
| 599 |
<h3 style="padding: 10px 6px 0px; margin:4px 0 0; cursor: default;"> |
| 600 |
<span style="cursor: default;"><?php echo __('Current one-time password', SIMBA_TFA_TEXT_DOMAIN).' '; |
| 601 |
if ($current_user->ID == $user_id) { echo $this->reset_current_otp_link(); } ?> |
| 602 |
</span> |
| 603 |
<div class="inside"> |
| 604 |
<p><strong style="font-size: 3em;"><?php echo $this->current_otp_code($tfa, $user_id); ?></strong></p> |
| 605 |
</div> |
| 606 |
</h3> |
| 607 |
<?php } else { |
| 608 |
?> |
| 609 |
<div class="inside"> |
| 610 |
<p class="simbatfa-frontend-current-otp" style="font-size: 1.5em; margin-top:6px;"> |
| 611 |
<strong> |
| 612 |
<?php echo __('Current one-time password', SIMBA_TFA_TEXT_DOMAIN).' '.$this->reset_current_otp_link(); ?> |
| 613 |
</strong> : |
| 614 |
|
| 615 |
<span class="simba_current_otp"><?php print $tfa->generateOTP($user_id, $tfa_priv_key_64); ?></span> |
| 616 |
|
| 617 |
</p> |
| 618 |
</div> |
| 619 |
|
| 620 |
<?php } ?> |
| 621 |
|
| 622 |
<?php if ($admin) { ?> |
| 623 |
<h3 style="padding-left: 10px; cursor: default;"> |
| 624 |
<span style="cursor: default;"><?php _e('QR code', SIMBA_TFA_TEXT_DOMAIN); ?></span> |
| 625 |
</h3> |
| 626 |
<?php } else { |
| 627 |
echo '<h2>'.__('QR code', SIMBA_TFA_TEXT_DOMAIN).'</h2>'; |
| 628 |
} ?> |
| 629 |
<div class="inside"> |
| 630 |
<p> |
| 631 |
<?php _e('For OTP apps that support scanning, scanning this code is the quickest way to set the app up (e.g. with Duo Mobile, Google Authenticator)', SIMBA_TFA_TEXT_DOMAIN); ?>. |
| 632 |
|
| 633 |
<?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); ?>. |
| 634 |
</p> |
| 635 |
<p title="<?php echo sprintf(__("Private key: %s (base 32: %s)", SIMBA_TFA_TEXT_DOMAIN), $tfa_priv_key, $tfa_priv_key_32);?>"> |
| 636 |
<?php $qr_url = $this->tfa_qr_code_url($algorithm_type, $url, $tfa_priv_key) ?> |
| 637 |
<div class="simbaotp_qr_container" data-qrcode="<?php echo esc_attr($qr_url); ?>"></div> |
| 638 |
</p> |
| 639 |
</div> |
| 640 |
|
| 641 |
<div class="inside"> |
| 642 |
|
| 643 |
<h3 class="normal" style="cursor: default"><?php _e('Private key - always to be kept secret - type this into your app to set it up (instead of scanning the code)', SIMBA_TFA_TEXT_DOMAIN); ?></h3> |
| 644 |
|
| 645 |
<p> |
| 646 |
<?php |
| 647 |
$this->print_private_keys($admin, 'full', $user_id); |
| 648 |
if ($current_user->ID == $user_id) { echo $this->reset_link($admin);} |
| 649 |
?> |
| 650 |
</p> |
| 651 |
</div> |
| 652 |
|
| 653 |
<?php |
| 654 |
if ($admin || apply_filters('simba_tfa_emergency_codes_user_settings', false, $user_id) !== false) { |
| 655 |
?> |
| 656 |
<div class="inside"> |
| 657 |
|
| 658 |
<h3 class="normal" style="cursor: default"><?php _e('Emergency codes', SIMBA_TFA_TEXT_DOMAIN); ?></h3> |
| 659 |
|
| 660 |
<p> |
| 661 |
<?php |
| 662 |
$default_text = '<a href="https://www.simbahosting.co.uk/s3/product/two-factor-authentication/">'.__('One-time emergency codes are a feature of the Premium version of this plugin.', SIMBA_TFA_TEXT_DOMAIN).'</a>'; |
| 663 |
echo apply_filters('simba_tfa_emergency_codes_user_settings', $default_text, $user_id); |
| 664 |
?> |
| 665 |
</p> |
| 666 |
|
| 667 |
</div> |
| 668 |
|
| 669 |
<?php } ?> |
| 670 |
|
| 671 |
</div> |
| 672 |
<?php |
| 673 |
} |
| 674 |
|
| 675 |
public function reset_current_otp_link($admin = true) { |
| 676 |
return '<a href="#" class="simbaotp_refresh">'.__('(update)', SIMBA_TFA_TEXT_DOMAIN).'</a>'; |
| 677 |
} |
| 678 |
|
| 679 |
public function advanced_settings_box($submit_button_callback = false) { |
| 680 |
$tfa = $this->getTFA(); |
| 681 |
|
| 682 |
global $current_user; |
| 683 |
$algorithm_type = $tfa->getUserAlgorithm($current_user->ID); |
| 684 |
|
| 685 |
?> |
| 686 |
<h2><?php _e('Advanced settings', SIMBA_TFA_TEXT_DOMAIN); ?></h2> |
| 687 |
|
| 688 |
<div id="tfa_advanced_box" class="tfa_settings_form" style="margin-top: 20px;"> |
| 689 |
|
| 690 |
<?php if (false === $submit_button_callback) { ?><form method="post" action="<?php print esc_url(add_query_arg('settings-updated', 'true', $_SERVER['REQUEST_URI'])); ?>"><?php } ?> |
| 691 |
|
| 692 |
<?php _e('Choose which algorithm for One Time Passwords you want to use.', SIMBA_TFA_TEXT_DOMAIN); ?> |
| 693 |
<p> |
| 694 |
<?php |
| 695 |
$this->tfaListAlgorithmRadios($current_user->ID); |
| 696 |
if($algorithm_type == 'hotp') |
| 697 |
{ |
| 698 |
$counter = $tfa->getUserCounter($current_user->ID); |
| 699 |
print '<br>'.__('Your counter on the server is currently on', SIMBA_TFA_TEXT_DOMAIN).': '.$counter; |
| 700 |
} |
| 701 |
?> |
| 702 |
|
| 703 |
</p> |
| 704 |
<?php if (false === $submit_button_callback) { submit_button(); echo '</form>'; } else { call_user_func($submit_button_callback); } ?> |
| 705 |
</div> |
| 706 |
<?php |
| 707 |
} |
| 708 |
|
| 709 |
public function login_enqueue_scripts() |
| 710 |
{ |
| 711 |
|
| 712 |
if(isset($_GET['action']) && $_GET['action'] != 'logout' && $_GET['action'] != 'login') return; |
| 713 |
|
| 714 |
// Prevent cacheing when in debug mode |
| 715 |
$script_ver = (defined('WP_DEBUG') && WP_DEBUG) ? time() : $this->version; |
| 716 |
|
| 717 |
wp_enqueue_script( 'tfa-ajax-request', SIMBA_TFA_PLUGIN_URL . '/includes/tfa.js', array( 'jquery' ), $script_ver ); |
| 718 |
$localize = array( |
| 719 |
'ajaxurl' => admin_url('admin-ajax.php'), |
| 720 |
'click_to_enter_otp' => __("Click to enter One Time Password", SIMBA_TFA_TEXT_DOMAIN), |
| 721 |
'enter_username_first' => __('You have to enter a username first.', SIMBA_TFA_TEXT_DOMAIN), |
| 722 |
'otp' => __("One Time Password (i.e. 2FA)", SIMBA_TFA_TEXT_DOMAIN), |
| 723 |
'otp_login_help' => __('(check your OTP app to get this password)', SIMBA_TFA_TEXT_DOMAIN), |
| 724 |
'nonce' => wp_create_nonce("simba_tfa_loginform_nonce") |
| 725 |
); |
| 726 |
// Spinner exists since WC 3.8. Use the proper functions to avoid SSL warnings. |
| 727 |
if (file_exists(ABSPATH.'wp-admin/images/spinner.gif')) { |
| 728 |
$localize['spinnerimg'] = admin_url('images/spinner.gif'); |
| 729 |
} elseif (file_exists(ABSPATH.WPINC.'/images/spinner.gif')) { |
| 730 |
$localize['spinnerimg'] = includes_url('images/spinner.gif'); |
| 731 |
} |
| 732 |
wp_localize_script( 'tfa-ajax-request', 'simba_tfasettings', $localize); |
| 733 |
} |
| 734 |
|
| 735 |
public function tfaShowHOTPOffSyncMessage() |
| 736 |
{ |
| 737 |
global $current_user; |
| 738 |
$is_off_sync = get_user_meta($current_user->ID, 'tfa_hotp_off_sync', true); |
| 739 |
if(!$is_off_sync) |
| 740 |
return; |
| 741 |
|
| 742 |
?> |
| 743 |
<div class="error"> |
| 744 |
<h3><?php _e('Two Factor Authentication re-sync needed', SIMBA_TFA_TEXT_DOMAIN);?></h3> |
| 745 |
<p> |
| 746 |
<?php _e('You need to resync your device for Two Factor Authentication since the OTP you last used is many steps ahead of the server.', SIMBA_TFA_TEXT_DOMAIN); ?> |
| 747 |
<br> |
| 748 |
<?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);?> |
| 749 |
<br><br> |
| 750 |
<a href="admin.php?page=two-factor-auth-user&warning_button_clicked=1" class="button"><?php _e('Click here and re-scan the QR-Code', SIMBA_TFA_TEXT_DOMAIN);?></a> |
| 751 |
</p> |
| 752 |
</div> |
| 753 |
|
| 754 |
<?php |
| 755 |
|
| 756 |
} |
| 757 |
|
| 758 |
// QR code image |
| 759 |
public function tfa_qr_code_url($algorithm_type, $url, $tfa_priv_key, $user_id = false){ |
| 760 |
global $current_user; |
| 761 |
|
| 762 |
if ($user_id == false) { |
| 763 |
$user = $current_user; |
| 764 |
} else { |
| 765 |
$user = get_user_by('id', $user_id); |
| 766 |
} |
| 767 |
|
| 768 |
$tfa = $this->getTFA(); |
| 769 |
|
| 770 |
// Old |
| 771 |
// $encode = 'otpauth://'.$algorithm_type.'/'.$url.':%2520'.$user->user_login.'%3Fsecret%3D'.Base32::encode($tfa_priv_key).'%26issuer='.$url.'%26counter='.$tfa->getUserCounter($user->ID); |
| 772 |
// |
| 773 |
// $ret = '<img src="https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl='.$encode.'">'; |
| 774 |
|
| 775 |
// New |
| 776 |
$encode = 'otpauth://'.$algorithm_type.'/'.$url.':'.$user->user_login.'?secret='.Base32::encode($tfa_priv_key).'&issuer='.$url.'&counter='.$tfa->getUserCounter($user->ID); |
| 777 |
|
| 778 |
// $ret = '<script>var qr_details = "'.$encode.'"</script>'; |
| 779 |
|
| 780 |
return $encode; |
| 781 |
} |
| 782 |
|
| 783 |
public function settings_intro_notices() { |
| 784 |
?> |
| 785 |
<p class="simba_tfa_personal_settings_notice simba_tfa_intro_notice"> |
| 786 |
<?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); ?> |
| 787 |
</p> |
| 788 |
<p class="simba_tfa_verify_tfa_notice simba_tfa_intro_notice"><strong> |
| 789 |
<?php _e('If you activate two-factor authentication, then verify that your two-factor application is showing the same One Time Password as shown on this page before you log out.', SIMBA_TFA_TEXT_DOMAIN); ?></strong> <?php if (current_user_can('manage_options')) { ?><a href="https://wordpress.org/plugins/two-factor-authentication/faq/"><?php _e('You should also bookmark the FAQs, which explain how to de-activate the plugin even if you cannot log in.', SIMBA_TFA_TEXT_DOMAIN);?></a><?php } ?> |
| 790 |
</p> |
| 791 |
<?php |
| 792 |
} |
| 793 |
|
| 794 |
public function plugins_loaded() { |
| 795 |
load_plugin_textdomain( |
| 796 |
SIMBA_TFA_TEXT_DOMAIN, |
| 797 |
false, |
| 798 |
dirname( plugin_basename( __FILE__ ) ) . '/languages/' |
| 799 |
); |
| 800 |
} |
| 801 |
|
| 802 |
public function load_frontend() { |
| 803 |
if (!class_exists('TFA_Frontend')) require_once(SIMBA_TFA_PLUGIN_DIR.'/includes/tfa_frontend.php'); |
| 804 |
if (empty($this->frontend)) $this->frontend = new TFA_Frontend($this); |
| 805 |
return $this->frontend; |
| 806 |
} |
| 807 |
|
| 808 |
public function shortcode_when_not_logged_in() { |
| 809 |
return ''; |
| 810 |
} |
| 811 |
|
| 812 |
// WooCommerce login form |
| 813 |
public function woocommerce_before_customer_login_form() { |
| 814 |
$script_ver = (defined('WP_DEBUG') && WP_DEBUG) ? time() : $this->version; |
| 815 |
wp_enqueue_script( 'tfa-wc-ajax-request', SIMBA_TFA_PLUGIN_URL.'/includes/wooextend.js', array('jquery'), $script_ver); |
| 816 |
$localize = array( |
| 817 |
'ajaxurl' => admin_url('admin-ajax.php'), |
| 818 |
'click_to_enter_otp' => __("Enter One Time Password (if you have one)", SIMBA_TFA_TEXT_DOMAIN), |
| 819 |
'enter_username_first' => __('You have to enter a username first.', SIMBA_TFA_TEXT_DOMAIN), |
| 820 |
'otp' => __("One Time Password", SIMBA_TFA_TEXT_DOMAIN), |
| 821 |
'nonce' => wp_create_nonce("simba_tfa_loginform_nonce"), |
| 822 |
'otp_login_help' => __('(check your OTP app to get this password)', SIMBA_TFA_TEXT_DOMAIN), |
| 823 |
); |
| 824 |
// Spinner exists since WC 3.8. Use the proper functions to avoid SSL warnings. |
| 825 |
if (file_exists(ABSPATH.'wp-admin/images/spinner.gif')) { |
| 826 |
$localize['spinnerimg'] = admin_url('images/spinner.gif'); |
| 827 |
} elseif (file_exists(ABSPATH.WPINC.'/images/spinner.gif')) { |
| 828 |
$localize['spinnerimg'] = includes_url('images/spinner.gif'); |
| 829 |
} |
| 830 |
|
| 831 |
wp_localize_script( 'tfa-wc-ajax-request', 'simbatfa_wc_settings', $localize); |
| 832 |
} |
| 833 |
|
| 834 |
} |
| 835 |
|
| 836 |
$simba_two_factor_authentication = new Simba_Two_Factor_Authentication(); |
| 837 |
|