PluginProbe
Two Factor Authentication / 1.2.6
Two Factor Authentication v1.2.6
1.12.2 1.13.0 1.14.10 1.14.11 1.14.14 1.14.15 1.14.16 1.14.17 1.14.23 1.14.24 1.14.26 1.14.27 1.14.3 1.14.4 1.14.5 1.14.7 1.14.8 1.15.5 1.16.0 1.2.10 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 All 98 releases
← All changes | two-factor-login.php +763 -218 1.16.01.2.6 View file →
@@ -2,290 +2,835 @@
2 2 /*
3 3 Plugin Name: Two Factor Authentication
4 4 Plugin URI: https://www.simbahosting.co.uk/s3/product/two-factor-authentication/
5 5 Description: Secure your WordPress login forms with two factor authentication - including WooCommerce login forms
6 -Author: David Anderson, original plugin by Oskar Hane and enhanced by Dee Nutbourne
6 +Author: David Nutbourne + David Anderson, original plugin by Oskar Hane
7 7 Author URI: https://www.simbahosting.co.uk
8 -Version: 1.16.0
9 -Text Domain: two-factor-authentication
10 -Domain Path: /languages
8 +Version: 1.2.6
11 9 License: GPLv2 or later
12 10 */
13 11
14 -register_activation_hook(__FILE__, 'simba_two_factor_authentication_activation');
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 15
16 -if (!function_exists('simba_two_factor_authentication_activation')) {
17 - function simba_two_factor_authentication_activation() {
18 - if (!empty($GLOBALS['simba_two_factor_authentication'])) {
19 - $is_2fa_plugin_active = false;
20 - $installed_plugins_slugs = array_keys(get_plugins());
21 - foreach ($installed_plugins_slugs as $installed_plugin_slug) {
22 - if (is_plugin_active($installed_plugin_slug)) {
23 - $temp_split_plugin_slug = explode('/', $installed_plugin_slug);
24 - if (isset($temp_split_plugin_slug[1]) && 'two-factor-login.php' == $temp_split_plugin_slug[1]) {
25 - $is_2fa_plugin_active = true;
26 - break;
27 - }
28 - }
29 - }
16 +class Simba_Two_Factor_Authentication {
30 17
31 - // We should prevent activation if and only if either the 2FA Premium or 2FA Free plugin is active.
32 - // We should not prevent activation if either the AIOS plugin is active.
33 - if ($is_2fa_plugin_active) {
34 - if (file_exists(__DIR__.'/simba-tfa/premium/loader.php')) {
35 - wp_die(esc_html__('To activate Two Factor Authentication Premium, first de-activate the free version (only one can be active at once).', 'two-factor-authentication'));
36 - } else { // If the 2FA Premium plugin is active and tries to activate the 2FA Free Plugin, it throws a fatal error and stops activating the free version.
37 - wp_die(esc_html__("You can't activate Two Factor Authentication (Free) because Two Factor Authentication Premium is active (only one can be active at once).", 'two-factor-authentication'));
38 - }
39 - }
40 - }
41 - }
42 -}
18 + public $version = '1.2.6';
19 + private $php_required = '5.3';
43 20
44 -if (!defined('SIMBA_TFA_TEXT_DOMAIN')) define('SIMBA_TFA_TEXT_DOMAIN', 'two-factor-authentication');
45 -if (!class_exists('Simba_Two_Factor_Authentication_1')) require dirname(__FILE__).'/simba-tfa/simba-tfa.php';
21 + private $frontend;
46 22
47 -if (!class_exists('Simba_Two_Factor_Authentication_Plugin')):
48 -/**
49 - * This parent-child relationship enables the two to be split without affecting backwards compatibility for developers making direct calls
50 - *
51 - * This class is for the plugin encapsulation.
52 - */
53 -class Simba_Two_Factor_Authentication_Plugin extends Simba_Two_Factor_Authentication_1 {
54 -
55 - public $version = '1.16.0';
56 -
57 - const PHP_REQUIRED = '5.6';
58 -
59 - /**
60 - * Constructor, run upon plugin initiation
61 - *
62 - * @uses __FILE__
63 - */
64 23 public function __construct() {
65 -
66 - add_action('plugins_loaded', array($this, 'plugins_loaded_load_textdomain'));
67 -
68 - add_action('init', array($this, 'init_child'));
69 -
70 - if (version_compare(PHP_VERSION, self::PHP_REQUIRED, '<' )) {
24 +
25 + if (version_compare(PHP_VERSION, $this->php_required, '<' )) {
71 26 add_action('all_admin_notices', array($this, 'admin_notice_insufficient_php'));
72 27 $abort = true;
73 28 }
74 -
75 - if (!function_exists('mcrypt_get_iv_size') && !function_exists('openssl_cipher_iv_length')) {
76 - add_action('all_admin_notices', array($this, 'admin_notice_missing_mcrypt_and_openssl'));
29 +
30 + if (!function_exists('mcrypt_get_iv_size')) {
31 + add_action('all_admin_notices', array($this, 'admin_notice_missing_mcrypt'));
77 32 $abort = true;
78 33 }
79 34
80 - $encryption_enabled = $this->get_option('tfa_encrypt_secrets');
81 - if ($encryption_enabled && (!defined('SIMBA_TFA_DB_ENCRYPTION_KEY') || '' === SIMBA_TFA_DB_ENCRYPTION_KEY)) {
82 - add_action('all_admin_notices', array($this, 'admin_notice_missing_db_encryption_key'));
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'));
83 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');
84 151
85 - if (!empty($abort)) return;
152 + $tfa = new Simba_TFA(new Base32(), new HOTP());
86 153
87 - // Menu entries
88 - add_action('admin_menu', array($this, 'menu_entry_for_admin'));
89 - add_action('admin_menu', array($this, 'menu_entry_for_user'));
90 - add_action('network_admin_menu', array($this, 'menu_entry_for_user'));
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();
91 209
92 - // Add settings link in plugin list
93 - $plugin = plugin_basename(__FILE__);
94 - add_filter("plugin_action_links_$plugin", array($this, 'add_plugin_settings_link'));
95 - add_filter("network_admin_plugin_action_links_$plugin", array($this, 'add_plugin_settings_link'));
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'];
96 215
97 - $this->set_user_settings_page_slug('two-factor-auth-user');
216 + $code_ok = $tfa->authUserFromLogin($params);
98 217
99 - $this->set_plugin_translate_url('https://translate.wordpress.org/projects/wp-plugins/two-factor-authentication/');
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));
100 221
101 - if (is_multisite() && function_exists('switch_to_blog')) {
102 - $main_site_id = function_exists('get_main_site_id') ? get_main_site_id() : 1;
103 - switch_to_blog($main_site_id);
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);
104 237 }
105 - $this->set_site_wide_administration_url(admin_url('options-general.php?page=two-factor-auth'));
106 - if (is_multisite() && function_exists('restore_current_blog')) restore_current_blog();
107 238
108 - $this->set_premium_version_url('https://www.simbahosting.co.uk/s3/product/two-factor-authentication/');
109 - $this->set_faq_url('https://wordpress.org/plugins/two-factor-authentication/#faq');
110 - parent::__construct();
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;
111 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>';
112 266 }
113 -
114 - /**
115 - * Runs upon the WP filters plugin_action_links_(plugin) and network_plugin_action_links_(plugin)
116 - *
117 - * @param Array $links
118 - *
119 - * @return Array
120 - */
121 - public function add_plugin_settings_link($links) {
122 - if (is_multisite()) {
123 - $main_site_id = function_exists('get_main_site_id') ? get_main_site_id() : 1;
124 - switch_to_blog($main_site_id);
125 - $link = $this->get_settings_link();
126 - restore_current_blog();
127 - array_unshift($links, $link);
128 - } else {
129 - $link = $this->get_settings_link();
130 - array_unshift($links, $link);
131 - }
132 267
133 - $link2 = '<a href="admin.php?page=two-factor-auth-user">'.__('User settings', 'two-factor-authentication').'</a>';
134 - array_unshift($links, $link2);
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));
135 274
136 - return $links;
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 + }
137 281 }
138 282
139 - /**
140 - * Get 2FA settings anchor tag link.
141 - *
142 - * @return string 2FA settings anchor tag link.
143 - */
144 - private function get_settings_link() {
145 - return '<a href="'.admin_url('options-general.php').'?page=two-factor-auth">'.__('Plugin settings', 'two-factor-authentication').'</a>';
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;
146 289 }
147 -
148 - /**
149 - * Runs upon the WP actions admin_menu and network_admin_menu
150 - */
151 - public function menu_entry_for_user() {
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();
152 306
153 - global $current_user;
154 - if ($this->is_activated_for_user($current_user->ID)) {
155 - add_menu_page(__('Two Factor Authentication', 'two-factor-authentication'), __('Two Factor Auth', 'two-factor-authentication'), 'read', 'two-factor-auth-user', array($this, 'show_dashboard_user_settings_page'), $this->includes_url().'/tfa_admin_icon_16x16.png', 72);
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";
156 313 }
314 +
157 315 }
158 -
159 - /**
160 - * Runs upon the WP action admin_menu
161 - */
162 - public function menu_entry_for_admin() {
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;
163 322
164 - $skip_adding_options_menu_entry = (is_multisite() && (!is_super_admin() || !is_main_site()));
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));
165 324
166 - $skip_adding_options_menu_entry = apply_filters('simba_tfa_skip_adding_options_menu_entry', $skip_adding_options_menu_entry);
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;
167 334
168 - if ($skip_adding_options_menu_entry) return;
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 + );
169 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 +
170 374 add_options_page(
171 - __('Two Factor Authentication', 'two-factor-authentication'),
172 - __('Two Factor Authentication', 'two-factor-authentication'),
173 - $this->get_management_capability(),
375 + __('Two Factor Authentication', SIMBA_TFA_TEXT_DOMAIN),
376 + __('Two Factor Authentication', SIMBA_TFA_TEXT_DOMAIN),
377 + 'manage_options',
174 378 'two-factor-auth',
175 - array($this, 'show_admin_settings_page')
379 + array($this, 'tfaShowAdminSettingsPage')
176 380 );
177 381 }
178 -
179 - /**
180 - * Include the admin settings page code
181 - */
182 - public function show_admin_settings_page() {
183 382
184 - if (!is_admin() || !current_user_can($this->get_management_capability())) return;
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 + }
185 394
186 - $admin_settings_links = array();
187 - if (!class_exists('Simba_Two_Factor_Authentication_Premium')) {
188 - $admin_settings_links[] = array(
189 - 'url' => 'https://www.simbahosting.co.uk/s3/product/two-factor-authentication/',
190 - 'title' => __('Premium version', 'two-factor-authentication'),
191 - );
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;
192 407 }
193 - $simba_tfa_support_url = apply_filters('simba_tfa_support_url', 'https://wordpress.org/support/plugin/two-factor-authentication/');
408 +
409 + }
194 410
195 - $admin_settings_links[] = array(
196 - 'url' => $simba_tfa_support_url,
197 - 'title' => __('Support', 'two-factor-authentication'),
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,
198 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());
199 572
200 - $admin_settings_links[] = array(
201 - 'url' => 'https://profiles.wordpress.org/davidanderson#content-plugins',
202 - 'title' => __('More free plugins', 'two-factor-authentication'),
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")
203 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;
204 741
205 - $admin_settings_links[] = array(
206 - 'url' => 'http://updraftplus.com',
207 - 'title' => 'UpdraftPlus - '.__('WordPress backups', 'two-factor-authentication'),
208 - );
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>
209 753
210 - $admin_settings_links[] = array(
211 - 'url' => 'https://www.simbahosting.co.uk/s3/shop/',
212 - 'title' => __('More premium plugins', 'two-factor-authentication'),
213 - );
754 + <?php
214 755
215 - $admin_settings_links[] = array(
216 - 'url' => 'https://twitter.com/updraftplus',
217 - 'title' => __('Twitter', 'two-factor-authentication'),
218 - );
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;
219 761
220 - $admin_settings_links[] = array(
221 - 'url' => 'https://david.dw-perspective.org.uk',
222 - 'title' => __("Lead developer's homepage", 'two-factor-authentication'),
223 - );
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.'">';
224 774
225 - $admin_settings_links = apply_filters('simba_tfa_admin_settings_links', $admin_settings_links);
775 + // New
776 + $encode = 'otpauth://'.$algorithm_type.'/'.$url.':'.$user->user_login.'?secret='.Base32::encode($tfa_priv_key).'&issuer='.$url.'&counter='.$tfa->getUserCounter($user->ID);
226 777
227 - $this->include_template('admin-settings.php', array(
228 - 'settings_page_heading' => $this->get_settings_page_heading(),
229 - 'admin_settings_links' => $admin_settings_links,
230 - ));
778 +// $ret = '<script>var qr_details = "'.$encode.'"</script>';
779 +
780 + return $encode;
231 781 }
232 -
233 - /**
234 - * Runs conditionally on the WP action all_admin_notices
235 - */
236 - public function admin_notice_insufficient_php() {
237 - /* translators: 1. PHP required 2. PHP version. */
238 - $this->show_admin_warning('<strong>'.__('Higher PHP version required', 'two-factor-authentication').'</strong><br> '.sprintf(__('The Two Factor Authentication plugin requires PHP version %1$s or higher - your current version is only %2$s.', 'two-factor-authentication'), self::PHP_REQUIRED, PHP_VERSION), 'error');
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
239 792 }
240 -
241 - /**
242 - * Runs conditionally on the WP action all_admin_notices
243 - */
244 - public function admin_notice_missing_mcrypt_and_openssl() {
245 - $this->show_admin_warning('<strong>'.__('PHP OpenSSL or mcrypt module required', 'two-factor-authentication').'</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');
246 - }
247 -
248 - /**
249 - * Runs conditionally on the WP action all_admin_notices
250 - */
251 - public function admin_notice_missing_db_encryption_key() {
252 - $this->show_admin_warning('<strong>'.__('Two Factor Authentication encryption key not found', 'two-factor-authentication').'</strong><br> '.htmlspecialchars(__('The "encrypt secrets" feature is currently enabled, but no encryption key has been found (set via the SIMBA_TFA_DB_ENCRYPTION_KEY constant).', 'two-factor-authentication').' '.__('This indicates that either setup failed, or your WordPress installation has been corrupted.', 'two-factor-authentication')) . ' <a href="' . esc_url($this->get_faq_url()) . '">'. __('Go here for the FAQs, which explain how a website owner can de-activate the plugin without needing to login.', 'two-factor-authentication') .'</a>', 'error');
253 - }
254 793
255 - /**
256 - * Run upon the WP plugins_loaded action. This method is called even if main loading aborts - so don't put anything else in it (use a separate method).
257 - */
258 - public function plugins_loaded_load_textdomain() {
794 + public function plugins_loaded() {
259 795 load_plugin_textdomain(
260 - 'two-factor-authentication',
796 + SIMBA_TFA_TEXT_DOMAIN,
261 797 false,
262 - dirname(plugin_basename(__FILE__)).'/languages/'
798 + dirname( plugin_basename( __FILE__ ) ) . '/languages/'
263 799 );
264 800 }
265 -
266 - /**
267 - * Run upon the WP init action. This method is called even if main loading aborts - so don't put anything else in it (use a separate method).
268 - */
269 - public function init_child() {
270 - /* translators: %s: plugin version. */
271 - $this->set_settings_page_heading(sprintf(__('Two Factor Authentication (Version: %s) - Admin Settings', 'two-factor-authentication'), $this->version));
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;
272 806 }
273 -}
274 -endif;
275 807
276 -$GLOBALS['simba_two_factor_authentication'] = new Simba_Two_Factor_Authentication_Plugin();
808 + public function shortcode_when_not_logged_in() {
809 + return '';
810 + }
277 811
278 -if (file_exists(__DIR__.'/simba-tfa/premium/loader.php') && empty($GLOBALS['simba_two_factor_authentication_premium'])) {
279 - if (!class_exists('Simba_Two_Factor_Authentication_Premium')) include_once(__DIR__.'/simba-tfa/premium/loader.php');
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 + }
280 830
281 - $GLOBALS['simba_two_factor_authentication_premium'] = new Simba_Two_Factor_Authentication_Premium($GLOBALS['simba_two_factor_authentication']);
831 + wp_localize_script( 'tfa-wc-ajax-request', 'simbatfa_wc_settings', $localize);
832 + }
282 833
283 - if (!class_exists('Updraft_Manager_Updater_1_9')) require_once(plugin_dir_path(__FILE__).'vendor/davidanderson684/simba-plugin-manager-updater/class-udm-updater.php');
834 +}
284 835
285 - try {
286 - new Updraft_Manager_Updater_1_9('https://www.simbahosting.co.uk/s3', 1, 'two-factor-authentication-premium/two-factor-login.php', array('require_login' => false));
287 - } catch (Exception $e) {
288 - // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Required for error handling.
289 - error_log($e->getMessage());
290 - }
291 -}
836 +$simba_two_factor_authentication = new Simba_Two_Factor_Authentication();