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