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