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