PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.4.0
WP 2FA – Two-factor authentication for WordPress v2.4.0
1.7.1 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.8.0 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0 3.0.1 3.1.0 3.1.1 3.1.1.2 trunk 1.2.0 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.1 1.6.2 1.7.0
wp-2fa / includes / classes / Admin / class-setup-wizard.php
wp-2fa / includes / classes / Admin Last commit date
Controllers 3 years ago Helpers 3 years ago SettingsPages 3 years ago Views 3 years ago class-help-contact-us.php 3 years ago class-premium-features.php 3 years ago class-settings-page.php 3 years ago class-settingspage.php 3 years ago class-setup-wizard.php 3 years ago class-user-listing.php 3 years ago class-user-notices.php 3 years ago class-user-profile.php 3 years ago class-user-registered.php 3 years ago class-user.php 3 years ago index.php 5 years ago
class-setup-wizard.php
665 lines
1 <?php
2 /**
3 * Setup wizard rendering class.
4 *
5 * @package wp2fa
6 * @subpackage setup
7 * @copyright 2023 WP White Security
8 * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
9 * @link https://wordpress.org/plugins/wp-2fa/
10 */
11
12 namespace WP2FA\Admin;
13
14 use WP2FA\Admin\User;
15 use \WP2FA\Core as Core;
16 use \WP2FA\WP2FA as WP2FA;
17 use WP2FA\Admin\Helpers\WP_Helper;
18 use WP2FA\Admin\Views\Wizard_Steps;
19 use WP2FA\Admin\Helpers\User_Helper;
20 use WP2FA\Admin\Controllers\Settings;
21 use \WP2FA\Utils\User_Utils as User_Utils;
22 use WP2FA\Admin\Views\First_Time_Wizard_Steps;
23 use \WP2FA\Admin\Settings_Page as Settings_Page;
24 use WP2FA\Utils\Settings_Utils as Settings_Utils;
25 use \WP2FA\Utils\Generate_Modal as Generate_Modal;
26 use WP2FA\Admin\SettingsPages\Settings_Page_Policies;
27 use \WP2FA\Authenticator\Authentication as Authentication;
28
29 /**
30 * Setup_Wizard class for the wizard steps setup
31 *
32 * @since 2.4.0
33 */
34 if ( ! class_exists( '\WP2FA\Admin\Setup_Wizard' ) ) {
35 /**
36 * Our class for creating a step by step wizard for easy configuration.
37 */
38 class Setup_Wizard {
39
40 /**
41 * Wizard Steps
42 *
43 * @var array
44 */
45 private static $wizard_steps;
46
47 /**
48 * Current Step
49 *
50 * @var string
51 */
52 private static $current_step;
53
54 /**
55 * Add setup admin page. This is empty on purpose.
56 */
57 public static function admin_menus() {
58 add_dashboard_page( '', '', 'read', 'wp-2fa-setup', '' );
59 }
60
61 /**
62 * Adding menus for multisite install
63 *
64 * @return void
65 *
66 * @since 2.2.0
67 */
68 public static function network_admin_menus() {
69 add_dashboard_page( 'index.php', '', 'read', 'wp-2fa-setup', '' );
70 }
71
72 /**
73 * Setup Page Start.
74 *
75 * @SuppressWarnings(PHPMD.ExitExpression)
76 */
77 public static function setup_page() {
78
79 // Get page argument from $_GET array.
80 $page = ( isset( $_GET['page'] ) ) ? \sanitize_text_field( \wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore
81 if ( empty( $page ) || 'wp-2fa-setup' !== $page ) {
82 return;
83 }
84
85 // Clear out any old notices.
86 $user = wp_get_current_user();
87
88 // First lets check if any options have been saved.
89 $settings_saved = true;
90 $settings = WP2FA::get_wp2fa_setting();
91 if ( empty( $settings ) || ! isset( $settings ) ) {
92 $settings_saved = false;
93 }
94
95 /**
96 * Wizard Steps.
97 */
98 $get_array = filter_input_array( INPUT_GET );
99 if ( isset( $get_array['wizard_type'] ) ) {
100 $wizard_type = sanitize_text_field( $get_array['wizard_type'] );
101 } else {
102 $wizard_type = 'default';
103 }
104
105 $is_user_forced_to_setup = User_Helper::get_user_enforced_instantly( $user );
106 if ( ! empty( $is_user_forced_to_setup ) ) {
107 add_filter( 'wp_2fa_wizard_default_steps', array( __CLASS__, 'wp_2fa_add_intro_step' ) );
108 }
109
110 $user_type = User_Utils::determine_user_2fa_status( $user );
111
112 $wizard_steps = array(
113 'welcome' => array(
114 'name' => esc_html__( 'Welcome', 'wp-2fa' ),
115 'content' => array( __CLASS__, 'wp_2fa_step_welcome' ),
116 'wizard_type' => 'welcome_wizard',
117 ),
118 'settings_configuration' => array(
119 'name' => esc_html__( 'Select 2FA Methods', 'wp-2fa' ),
120 'content' => array( __CLASS__, 'wp_2fa_step_global_2fa_methods' ),
121 'save' => array( __CLASS__, 'wp_2fa_step_global_2fa_methods_save' ),
122 'wizard_type' => 'welcome_wizard',
123 ),
124 'finish' => array(
125 'name' => esc_html__( 'Setup Finish', 'wp-2fa' ),
126 'content' => array( __CLASS__, 'wp_2fa_step_finish' ),
127 'save' => array( __CLASS__, 'wp_2fa_step_finish_save' ),
128 'wizard_type' => 'welcome_wizard',
129 ),
130 );
131
132 // Admin user setting up fresh install of 2FA plugin.
133 if ( in_array( 'can_manage_options', $user_type, true ) && ! $settings_saved ) {
134 unset( $wizard_steps['user_choose_2fa_method'] );
135 unset( $wizard_steps['reconfigure_method'] );
136 }
137
138 // We will use this setting to determine if defaults have already been saved to the DB.
139 $have_defaults_been_applied = Settings_Utils::get_option( 'default_settings_applied', false );
140 // If we have settings, but they are the defaults, then we want to consider the settings to be unsaved at this point.
141 if ( in_array( 'can_manage_options', $user_type, true ) && $settings_saved && $have_defaults_been_applied ) {
142 $settings_saved = false;
143 }
144
145 // Ensure user has minimum capabitlies needed to be here.
146 if ( in_array( 'can_read', $user_type, true ) && $settings_saved ) {
147
148 switch ( $wizard_type ) {
149 case 'user_2fa_config':
150 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( array( 'user_choose_2fa_method', 'setup_method', 'finish', 'backup_codes' ) ) );
151 break;
152
153 case 'backup_codes_config':
154 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( array( 'backup_codes' ) ) );
155 break;
156
157 case 'user_reconfigure_config':
158 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( array( 'reconfigure_method' ) ) );
159 break;
160
161 default:
162 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( array( 'choose_2fa_method', 'setup_method', 'finish', 'backup_codes', 'reconfigure_method' ) ) );
163 }
164
165 // Remove 1st step if only one method is available.
166 if ( empty( WP2FA::get_wp2fa_setting( 'enable_totp' ) ) || empty( WP2FA::get_wp2fa_setting( 'enable_email' ) ) ) {
167 unset( $wizard_steps['choose_2fa_method'] );
168 }
169
170 // If the user has codes setup already, no need to add the slide.
171 if ( ! in_array( 'user_needs_to_setup_backup_codes', $user_type, true ) && 'backup_codes_config' !== $wizard_type ) {
172 unset( $wizard_steps['backup_codes'] );
173 }
174 }
175
176 /**
177 * Filter: `Wizard Default Steps`
178 *
179 * WSAL filter to filter wizard steps before they are displayed.
180 *
181 * @param array $wizard_steps – Wizard Steps.
182 */
183 self::$wizard_steps = apply_filters( WP_2FA_PREFIX . 'wizard_default_steps', $wizard_steps );
184
185 // Set current step.
186 $current_step = ( isset( $_GET['current-step'] ) ) ? \sanitize_text_field( \wp_unslash( $_GET['current-step'] ) ) : ''; // phpcs:ignore
187 self::$current_step = ! empty( $current_step ) ? $current_step : current( array_keys( self::$wizard_steps ) );
188
189 if ( 'backup_codes' === self::$current_step && ! Settings_Page::are_backup_codes_enabled( User_Helper::get_user_role( $user ) ) ) {
190
191 $redirect_to_finish = add_query_arg(
192 array(
193 'current-step' => 'finish',
194 'all-set' => 1,
195 )
196 );
197 wp_safe_redirect( esc_url_raw( $redirect_to_finish ) );
198 }
199
200 /**
201 * Enqueue Scripts.
202 */
203 wp_enqueue_style(
204 'wp_2fa_setup_wizard',
205 Core\style_url( 'setup-wizard', 'admin' ),
206 array( 'select2' ),
207 WP_2FA_VERSION
208 );
209
210 wp_enqueue_style(
211 'wp_2fa_admin-style',
212 Core\style_url( 'admin-style', 'admin' ),
213 array(),
214 WP_2FA_VERSION
215 );
216
217 \WP2FA\Core\enqueue_select2_scripts();
218
219 if ( \WP2FA\Admin\Helpers\WP_Helper::is_multisite() ) {
220 \WP2FA\Core\enqueue_multi_select_scripts();
221 }
222
223 wp_enqueue_script(
224 'wp_2fa_admin',
225 Core\script_url( 'admin', 'admin' ),
226 array( 'jquery-ui-widget', 'jquery-ui-core', 'jquery-ui-autocomplete', 'select2' ),
227 WP_2FA_VERSION,
228 true
229 );
230
231 wp_enqueue_script(
232 'wp_2fa_micromodal',
233 Core\script_url( 'micromodal', 'admin', 'select2' ),
234 array(),
235 WP_2FA_VERSION,
236 true
237 );
238
239 // Data array.
240 $data_array = array(
241 'ajaxURL' => admin_url( 'admin-ajax.php' ),
242 'roles' => WP2FA::wp_2fa_get_roles(),
243 'nonce' => wp_create_nonce( 'wp-2fa-settings-nonce' ),
244 'invalidEmail' => esc_html__( 'Please use a valid email address', 'wp-2fa' ),
245 );
246 wp_localize_script( 'wp_2fa_admin', 'wp2faData', $data_array );
247
248 // Data array.
249 $data_array = array(
250 'ajaxURL' => admin_url( 'admin-ajax.php' ),
251 'nonce' => wp_create_nonce( 'wp2fa-verify-wizard-page' ),
252 'codesPreamble' => esc_html__( 'These are the 2FA backup codes for the user', 'wp-2fa' ),
253 'readyText' => esc_html__( 'I\'m ready', 'wp-2fa' ),
254 'codeReSentText' => esc_html__( 'New code sent', 'wp-2fa' ),
255 );
256
257 /**
258 * Gives the ability to change the default JS wizard settings.
259 *
260 * @param int $data_array - The array with all the JS wizard settings.
261 *
262 * @since 2.2.0
263 */
264 $data_array = apply_filters( WP_2FA_PREFIX . 'js_wizard_settings', $data_array );
265 wp_localize_script( 'wp_2fa_admin', 'wp2faWizardData', $data_array );
266
267 /**
268 * Save Wizard Settings.
269 */
270 $save_step = ( isset( $_POST['save_step'] ) ) ? \sanitize_text_field( \wp_unslash( $_POST['save_step'] ) ) : ''; // phpcs:ignore
271 if ( ! empty( $save_step ) && ! empty( self::$wizard_steps[ self::$current_step ]['save'] ) ) {
272 call_user_func( self::$wizard_steps[ self::$current_step ]['save'] );
273 }
274
275 self::setup_page_header();
276 self::setup_page_steps();
277 self::setup_page_content();
278 self::setup_page_footer();
279
280 exit();
281 }
282
283 /**
284 * Setup Page Header.
285 */
286 private static function setup_page_header() {
287 ?>
288 <!DOCTYPE html>
289 <html <?php language_attributes(); ?>>
290 <head>
291 <meta name="viewport" content="width=device-width" />
292 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
293 <title><?php esc_html_e( 'WP 2FA &rsaquo; Setup Wizard', 'wp-2fa' ); ?></title>
294 <?php wp_print_scripts( 'jquery' ); ?>
295 <?php wp_print_scripts( 'jquery-ui-core' ); ?>
296 <?php wp_print_scripts( 'wp_2fa_setup_wizard' ); ?>
297 <?php wp_print_scripts( 'wp_2fa_micromodal' ); ?>
298 <?php wp_print_scripts( 'wp_2fa_admin' ); ?>
299 <?php wp_print_scripts( 'multi-site-select' ); ?>
300 <?php
301 /**
302 * Gives the ability for 3rd party scripts to add their own JS to the plugin setup page.
303 *
304 * @since 2.2.0
305 */
306 \do_action( WP_2FA_PREFIX . 'setup_page_scripts' );
307 ?>
308 <?php wp_print_styles( 'common' ); ?>
309 <?php wp_print_styles( 'forms' ); ?>
310 <?php wp_print_styles( 'buttons' ); ?>
311 <?php wp_print_styles( 'wp-jquery-ui-dialog' ); ?>
312 <?php wp_print_styles( 'wp_2fa_admin' ); ?>
313 <?php do_action( 'admin_print_styles' ); ?>
314 </head>
315 <body class="wp2fa-setup wp-core-ui">
316 <div class="setup-wizard-wrapper wp-2fa-settings-wrapper wp2fa-form-styles">
317 <h1 id="wp2fa-logo"><a href="https://wpsecurityauditlog.com" target="_blank"><img style="max-width: 80px;" src="<?php echo esc_url( WP_2FA_URL . 'dist/images/wp-2fa-color_opt.png' ); ?>"></a></h1>
318 <?php
319 }
320
321 /**
322 * Setup Page Footer.
323 */
324 private static function setup_page_footer() {
325 $user = wp_get_current_user();
326
327 $redirect = Settings::get_settings_page_link();
328 ?>
329 <div class="wp2fa-setup-footer">
330 <?php if ( 'welcome' !== self::$current_step && 'finish' !== self::$current_step ) { // Don't show the link on the first & last step. ?>
331 <?php if ( ! User_Helper::get_user_enforced_instantly( $user ) ) { ?>
332 <a class="close-wizard-link" href="<?php echo esc_url( $redirect ); ?>"><?php esc_html_e( 'Close Wizard', 'wp-2fa' ); ?></a>
333 <?php
334 }
335 }
336 ?>
337 </div>
338 </div>
339 </body>
340 </html>
341 <?php
342 // phpcs:ignore
343 echo Generate_Modal::generate_modal(
344 'notify-admin-settings-page',
345 '',
346 __( 'If you cancel this wizard, the default plugin settings will be applied. You can always configure the plugin settings and two-factor authentication policies at a later stage from the ', 'wp-2fa' ) . ' <b>' . __( 'WP 2FA', 'wp-2fa' ) . '</b>' . __( ' entry in your WordPress dashboard menu.', 'wp-2fa' ),
347 array(
348 '<a href="#" id="close-settings" class="button button-primary wp-2fa-button-primary" data-redirect-url="' . esc_url( $redirect ) . '">' . __( 'OK, close wizard', 'wp-2fa' ) . '</a>',
349 '<a href="#" class="button button-secondary wp-2fa-button-secondary wp-2fa-button-secondary" data-close-2fa-modal>' . __( 'Continue with wizard', 'wp-2fa' ) . '</a>',
350 ),
351 '',
352 '580px'
353 );
354 ?>
355 <?php
356 }
357
358 /**
359 * Setup Page Steps.
360 */
361 private static function setup_page_steps() {
362 ?>
363 <ul class="steps">
364 <?php
365 foreach ( self::$wizard_steps as $key => $step ) :
366 if ( 'welcome_wizard' === $step['wizard_type'] || is_array( $step['wizard_type'] ) && in_array( 'welcome_wizard', $step['wizard_type'], true ) ) :
367 if ( $key === self::$current_step ) :
368 ?>
369 <li class="is-active"><?php echo esc_html( $step['name'] ); ?></li>
370 <?php
371 else :
372 ?>
373 <li><?php echo esc_html( $step['name'] ); ?></li>
374 <?php
375 endif;
376 endif;
377 endforeach;
378 ?>
379 </ul>
380 <?php
381 }
382
383 /**
384 * Get Next Step URL.
385 *
386 * @return string
387 */
388 private static function get_next_step() {
389 // Get current step.
390 $current_step = self::$current_step;
391
392 // Array of step keys.
393 $keys = array_keys( self::$wizard_steps );
394 if ( end( $keys ) === $current_step ) { // If last step is active then return WP Admin URL.
395 return admin_url();
396 }
397
398 // Search for step index in step keys.
399 $step_index = array_search( $current_step, $keys, true );
400 if ( false === $step_index ) { // If index is not found then return empty string.
401 return '';
402 }
403
404 // Return next step.
405 return add_query_arg( 'current-step', $keys[ $step_index + 1 ] );
406 }
407
408 /**
409 * Setup Page Content.
410 */
411 private static function setup_page_content() {
412 ?>
413 <div class="wp2fa-setup-content">
414 <?php
415 if ( ! empty( self::$wizard_steps[ self::$current_step ]['content'] ) ) {
416 call_user_func( self::$wizard_steps[ self::$current_step ]['content'] );
417 }
418 ?>
419 </div>
420 <?php
421 }
422
423 /**
424 * Step View: `Welcome`
425 */
426 private static function wp_2fa_step_welcome() {
427 Wizard_Steps::welcome_step( self::get_next_step() );
428 }
429
430 /**
431 * Step View: `Finish`
432 */
433 private static function wp_2fa_step_finish() {
434 $wp2fa_user = User::get_instance();
435 User_Helper::remove_user_needs_to_reconfigure_2fa( $wp2fa_user->get_2fa_wp_user() );
436 Wizard_Steps::congratulations_step( true );
437 }
438
439 /**
440 * Step Save: `Finish`
441 *
442 * @SuppressWarnings(PHPMD.ExitExpression)
443 */
444 private static function wp_2fa_step_finish_save() {
445 // Verify nonce.
446 check_admin_referer( 'wp2fa-step-finish' );
447 wp_safe_redirect( esc_url_raw( self::get_next_step() ) );
448 exit();
449 }
450
451 /**
452 * Step View: `Choose Methods`
453 */
454 private static function wp_2fa_step_global_2fa_methods() {
455 ?>
456 <form method="post" class="wp2fa-setup-form wp2fa-form-styles" autocomplete="off">
457 <?php wp_nonce_field( 'wp2fa-step-choose-method' ); ?>
458 <div class="step-setting-wrapper active" data-step-title="<?php esc_html_e( 'Choose 2FA methods', 'wp-2fa' ); ?>">
459 <?php First_Time_Wizard_Steps::select_method( true ); ?>
460 <div class="wp2fa-setup-actions">
461 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Continue Setup', 'wp-2fa' ); ?>"><?php esc_html_e( 'Continue Setup', 'wp-2fa' ); ?></a>
462 </div>
463 </div>
464 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Choose backup methods', 'wp-2fa' ); ?>">
465 <?php First_Time_Wizard_Steps::backup_method( true ); ?>
466 <div class="wp2fa-setup-actions">
467 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Continue Setup', 'wp-2fa' ); ?>"><?php esc_html_e( 'Continue Setup', 'wp-2fa' ); ?></a>
468 </div>
469 </div>
470 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( '2FA policy', 'wp-2fa' ); ?>">
471 <?php First_Time_Wizard_Steps::enforcement_policy( true ); ?>
472 <div class="wp2fa-setup-actions">
473 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Continue Setup', 'wp-2fa' ); ?>"><?php esc_html_e( 'Continue Setup', 'wp-2fa' ); ?></a>
474 </div>
475 </div>
476 <div class="step-setting-wrapper hidden" data-step-title="<?php esc_html_e( 'Exclude users', 'wp-2fa' ); ?>">
477 <?php First_Time_Wizard_Steps::exclude_users( true ); ?>
478 <div class="wp2fa-setup-actions">
479 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Continue Setup', 'wp-2fa' ); ?>"><?php esc_html_e( 'Continue Setup', 'wp-2fa' ); ?></a>
480 </div>
481 </div>
482
483 <?php if ( WP_Helper::is_multisite() ) : ?>
484 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Exclude sites', 'wp-2fa' ); ?>">
485 <?php First_Time_Wizard_Steps::excluded_network_sites( true ); ?>
486 <div class="wp2fa-setup-actions">
487 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Continue Setup', 'wp-2fa' ); ?>"><?php esc_html_e( 'Continue Setup', 'wp-2fa' ); ?></a>
488 </div>
489 </div>
490 <?php endif; ?>
491
492 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Grace period', 'wp-2fa' ); ?>">
493 <h3><?php esc_html_e( 'How long should the grace period for your users be?', 'wp-2fa' ); ?></h3>
494 <p class="description"><?php esc_html_e( 'When you configure the 2FA policies and require users to configure 2FA, they can either have a grace period to configure 2FA, or can be required to configure 2FA before the next time they login. Choose which method you\'d like to use:', 'wp-2fa' ); ?></p>
495 <?php First_Time_Wizard_Steps::grace_period( true ); ?>
496 <div class="wp2fa-setup-actions">
497 <button class="button button-primary save-wizard" type="submit" name="save_step" value="<?php esc_attr_e( 'All done', 'wp-2fa' ); ?>"><?php esc_html_e( 'All done', 'wp-2fa' ); ?></button>
498 </div>
499 </div>
500
501 </form>
502 <?php
503 }
504
505 /**
506 * Step Save: `Choose Method`
507 *
508 * @SuppressWarnings(PHPMD.ExitExpression)
509 */
510 private static function wp_2fa_step_global_2fa_methods_save() {
511 // Check nonce.
512 check_admin_referer( 'wp2fa-step-choose-method' );
513
514 $input = ( isset( $_POST[ WP_2FA_POLICY_SETTINGS_NAME ] ) ) ? wp_unslash( $_POST[ WP_2FA_POLICY_SETTINGS_NAME ] ) : array(); // phpcs:ignore
515
516 if ( ! WP_Helper::is_multisite() ) {
517 unregister_setting(
518 WP_2FA_POLICY_SETTINGS_NAME,
519 WP_2FA_POLICY_SETTINGS_NAME
520 );
521 }
522 $settings_page = new Settings_Page_Policies();
523 $sanitized_settings = $settings_page->validate_and_sanitize( $input, 'setup_wizard' );
524 WP2FA::update_plugin_settings( $sanitized_settings );
525
526 wp_safe_redirect( esc_url_raw( self::get_next_step() ) );
527 exit();
528 }
529
530 /**
531 * Send email with fresh code, or to setup email 2fa.
532 *
533 * @param int $user_id User id we want to send the message to.
534 * @param string $nominated_email_address - The user custom address to use (name of the meta key to check for).
535 *
536 * @return bool
537 *
538 * @SuppressWarnings(PHPMD.ExitExpression)
539 */
540 public static function send_authentication_setup_email( $user_id, $nominated_email_address = 'nominated_email_address' ) {
541
542 // If we have a nonce posted, check it.
543 if ( \wp_doing_ajax() && isset( $_POST['nonce'] ) ) {
544 $nonce_check = \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['nonce'] ) ), 'wp-2fa-send-setup-email' );
545 if ( ! $nonce_check ) {
546 return false;
547 }
548 }
549
550 if ( isset( $_POST['user_id'] ) ) {
551 $user = get_userdata( intval( $_POST['user_id'] ) );
552 } else {
553 $user = get_userdata( $user_id );
554 }
555
556 // Grab email address is its provided.
557 if ( isset( $_POST['email_address'] ) ) {
558 $email = sanitize_email( \wp_unslash( $_POST['email_address'] ) );
559 } else {
560 $email = sanitize_email( $user->user_email );
561 }
562
563 if ( wp_doing_ajax() && isset( $_POST['nonce'] ) ) {
564 update_user_meta( $user->ID, WP_2FA_PREFIX . 'nominated_email_address', $email );
565 }
566
567 $enabled_email_address = '';
568 if ( ! empty( $nominated_email_address ) ) {
569 $enabled_email_address = get_user_meta( $user->ID, WP_2FA_PREFIX . $nominated_email_address, true );
570 }
571
572 // Generate a token and setup email.
573 $token = Authentication::generate_token( $user->ID );
574
575
576 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_subject' ), $user->ID ) );
577 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_body' ), $user->ID, $token ) );
578
579 if ( ! empty( $enabled_email_address ) ) {
580 $email_address = $enabled_email_address;
581 } else {
582 $email_address = $user->user_email;
583 }
584
585 return Settings_Page::send_email( $email_address, $subject, $message );
586 }
587
588 /**
589 * Send email to setup authentication
590 */
591 public static function regenerate_authentication_key() {
592 // Grab current user.
593 $user = wp_get_current_user();
594
595 $key = Authentication::generate_key();
596
597 $site_name = site_url();
598 $site_name = trim( str_replace( array( 'http://', 'https://' ), '', $site_name ), '/' );
599
600 /**
601 * Changing the title of the login screen for the TOTP method.
602 *
603 * @param string $title - The default title.
604 * @param \WP_User $user - The WP user.
605 *
606 * @since 2.0.0
607 */
608 $totp_title = apply_filters( WP_2FA_PREFIX . 'totp_title', $site_name . ':' . $user->user_login, $user );
609 $new_qr = Authentication::get_google_qr_code( $totp_title, $key, $site_name );
610
611 wp_send_json_success(
612 array(
613 'key' => Authentication::decrypt_key_if_needed( $key ),
614 'qr' => $new_qr,
615 )
616 );
617 }
618
619 /**
620 * 3rd Party plugins
621 *
622 * @param array $wizard_steps - Array with the current wizard steps.
623 *
624 * @return array
625 */
626 public static function wp_2fa_add_intro_step( $wizard_steps ) {
627 $new_wizard_steps = array(
628 'test' => array(
629 'name' => __( 'Welcome to WP 2FA', 'wp-2fa' ),
630 'content' => array( __CLASS__, 'introduction_step' ),
631 'save' => array( __CLASS__, 'introduction_step_save' ),
632 'wizard_type' => 'welcome_wizard',
633 ),
634 );
635
636 // combine the two arrays.
637 $wizard_steps = $new_wizard_steps + $wizard_steps;
638
639 return $wizard_steps;
640 }
641
642 /**
643 * Shows introduction step of the wizard
644 *
645 * @return void
646 */
647 private static function introduction_step() {
648 Wizard_Steps::introduction_step();
649 }
650
651 /**
652 * Step Save: `Addons`
653 *
654 * @SuppressWarnings(PHPMD.ExitExpression)
655 */
656 private static function introduction_step_save() {
657 // Check nonce.
658 check_admin_referer( 'wp2fa-step-addon' );
659
660 wp_safe_redirect( esc_url_raw( self::get_next_step() ) );
661 exit();
662 }
663 }
664 }
665