PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.4.2
WP 2FA – Two-factor authentication for WordPress v2.4.2
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
722 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__( 'Configure 2FA methods & Policies', '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 'backupCodesSent' => esc_html__( 'Backup codes sent', 'wp-2fa' ),
246 );
247 wp_localize_script( 'wp_2fa_admin', 'wp2faData', $data_array );
248
249 // Data array.
250 $data_array = array(
251 'ajaxURL' => admin_url( 'admin-ajax.php' ),
252 'nonce' => wp_create_nonce( 'wp2fa-verify-wizard-page' ),
253 'codesPreamble' => esc_html__( 'These are the 2FA backup codes for the user', 'wp-2fa' ),
254 'readyText' => esc_html__( 'I\'m ready', 'wp-2fa' ),
255 'codeReSentText' => esc_html__( 'New code sent', 'wp-2fa' ),
256 );
257
258 /**
259 * Gives the ability to change the default JS wizard settings.
260 *
261 * @param int $data_array - The array with all the JS wizard settings.
262 *
263 * @since 2.2.0
264 */
265 $data_array = apply_filters( WP_2FA_PREFIX . 'js_wizard_settings', $data_array );
266 wp_localize_script( 'wp_2fa_admin', 'wp2faWizardData', $data_array );
267
268 /**
269 * Save Wizard Settings.
270 */
271 $save_step = ( isset( $_POST['save_step'] ) ) ? \sanitize_text_field( \wp_unslash( $_POST['save_step'] ) ) : ''; // phpcs:ignore
272 if ( ! empty( $save_step ) && ! empty( self::$wizard_steps[ self::$current_step ]['save'] ) ) {
273 call_user_func( self::$wizard_steps[ self::$current_step ]['save'] );
274 }
275
276 self::setup_page_header();
277 self::setup_page_steps();
278 self::setup_page_content();
279 self::setup_page_footer();
280
281 exit();
282 }
283
284 /**
285 * Setup Page Header.
286 */
287 private static function setup_page_header() {
288 ?>
289 <!DOCTYPE html>
290 <html <?php language_attributes(); ?>>
291 <head>
292 <meta name="viewport" content="width=device-width" />
293 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
294 <title><?php esc_html_e( 'WP 2FA &rsaquo; Setup Wizard', 'wp-2fa' ); ?></title>
295 <?php wp_print_scripts( 'jquery' ); ?>
296 <?php wp_print_scripts( 'jquery-ui-core' ); ?>
297 <?php wp_print_scripts( 'wp_2fa_setup_wizard' ); ?>
298 <?php wp_print_scripts( 'wp_2fa_micromodal' ); ?>
299 <?php wp_print_scripts( 'wp_2fa_admin' ); ?>
300 <?php wp_print_scripts( 'multi-site-select' ); ?>
301 <?php
302 /**
303 * Gives the ability for 3rd party scripts to add their own JS to the plugin setup page.
304 *
305 * @since 2.2.0
306 */
307 \do_action( WP_2FA_PREFIX . 'setup_page_scripts' );
308 ?>
309 <?php wp_print_styles( 'common' ); ?>
310 <?php wp_print_styles( 'forms' ); ?>
311 <?php wp_print_styles( 'buttons' ); ?>
312 <?php wp_print_styles( 'wp-jquery-ui-dialog' ); ?>
313 <?php wp_print_styles( 'wp_2fa_admin' ); ?>
314 <?php do_action( 'admin_print_styles' ); ?>
315 </head>
316 <body class="wp2fa-setup wp-core-ui">
317 <div class="setup-wizard-wrapper wp-2fa-settings-wrapper wp2fa-form-styles">
318 <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>
319 <?php
320 }
321
322 /**
323 * Setup Page Footer.
324 */
325 private static function setup_page_footer() {
326 $user = wp_get_current_user();
327
328 $redirect = Settings::get_settings_page_link();
329 ?>
330 <div class="wp2fa-setup-footer">
331 <?php if ( 'welcome' !== self::$current_step && 'finish' !== self::$current_step ) { // Don't show the link on the first & last step. ?>
332 <?php if ( ! User_Helper::get_user_enforced_instantly( $user ) ) { ?>
333 <a class="close-wizard-link" href="<?php echo esc_url( $redirect ); ?>"><?php esc_html_e( 'Close Wizard', 'wp-2fa' ); ?></a>
334 <?php
335 }
336 }
337 ?>
338 </div>
339 </div>
340 </body>
341 </html>
342 <?php
343 // phpcs:ignore
344 echo Generate_Modal::generate_modal(
345 'notify-admin-settings-page',
346 '',
347 __( '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' ),
348 array(
349 '<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>',
350 '<a href="#" class="button button-secondary wp-2fa-button-secondary wp-2fa-button-secondary" data-close-2fa-modal>' . __( 'Continue with wizard', 'wp-2fa' ) . '</a>',
351 ),
352 '',
353 '580px'
354 );
355 ?>
356 <?php
357 }
358
359 /**
360 * Setup Page Steps.
361 */
362 private static function setup_page_steps() {
363 ?>
364 <ul class="steps">
365 <?php
366 foreach ( self::$wizard_steps as $key => $step ) :
367 if ( 'welcome_wizard' === $step['wizard_type'] || is_array( $step['wizard_type'] ) && in_array( 'welcome_wizard', $step['wizard_type'], true ) ) :
368 if ( $key === self::$current_step ) :
369 ?>
370 <li class="is-active"><?php echo esc_html( $step['name'] ); ?></li>
371 <?php
372 else :
373 ?>
374 <li><?php echo esc_html( $step['name'] ); ?></li>
375 <?php
376 endif;
377 endif;
378 endforeach;
379 ?>
380 </ul>
381 <?php
382 }
383
384 /**
385 * Get Next Step URL.
386 *
387 * @return string
388 */
389 private static function get_next_step() {
390 // Get current step.
391 $current_step = self::$current_step;
392
393 // Array of step keys.
394 $keys = array_keys( self::$wizard_steps );
395 if ( end( $keys ) === $current_step ) { // If last step is active then return WP Admin URL.
396 return admin_url();
397 }
398
399 // Search for step index in step keys.
400 $step_index = array_search( $current_step, $keys, true );
401 if ( false === $step_index ) { // If index is not found then return empty string.
402 return '';
403 }
404
405 // Return next step.
406 return add_query_arg( 'current-step', $keys[ $step_index + 1 ] );
407 }
408
409 /**
410 * Setup Page Content.
411 */
412 private static function setup_page_content() {
413 ?>
414 <div class="wp2fa-setup-content">
415 <?php
416 if ( ! empty( self::$wizard_steps[ self::$current_step ]['content'] ) ) {
417 call_user_func( self::$wizard_steps[ self::$current_step ]['content'] );
418 }
419 ?>
420 </div>
421 <?php
422 }
423
424 /**
425 * Step View: `Welcome`
426 */
427 private static function wp_2fa_step_welcome() {
428 Wizard_Steps::welcome_step( self::get_next_step() );
429 }
430
431 /**
432 * Step View: `Finish`
433 */
434 private static function wp_2fa_step_finish() {
435 $wp2fa_user = User::get_instance();
436 User_Helper::remove_user_needs_to_reconfigure_2fa( $wp2fa_user->get_2fa_wp_user() );
437 Wizard_Steps::congratulations_step( true );
438 }
439
440 /**
441 * Step Save: `Finish`
442 *
443 * @SuppressWarnings(PHPMD.ExitExpression)
444 */
445 private static function wp_2fa_step_finish_save() {
446 // Verify nonce.
447 check_admin_referer( 'wp2fa-step-finish' );
448 wp_safe_redirect( esc_url_raw( self::get_next_step() ) );
449 exit();
450 }
451
452 /**
453 * Step View: `Choose Methods`
454 */
455 private static function wp_2fa_step_global_2fa_methods() {
456 ?>
457 <form method="post" class="wp2fa-setup-form wp2fa-form-styles" autocomplete="off">
458 <?php wp_nonce_field( 'wp2fa-step-choose-method' ); ?>
459 <div class="step-setting-wrapper active" data-step-title="<?php esc_html_e( '2FA methods', 'wp-2fa' ); ?>">
460 <?php First_Time_Wizard_Steps::select_method( true ); ?>
461 <div class="wp2fa-setup-actions">
462 <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>
463 </div>
464 </div>
465 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Alternative methods', 'wp-2fa' ); ?>">
466 <?php First_Time_Wizard_Steps::backup_method( true ); ?>
467 <div class="wp2fa-setup-actions">
468 <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>
469 </div>
470 </div>
471 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( '2FA policy', 'wp-2fa' ); ?>">
472 <?php First_Time_Wizard_Steps::enforcement_policy( true ); ?>
473 <div class="wp2fa-setup-actions">
474 <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>
475 <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>
476 </div>
477 </div>
478 <div class="step-setting-wrapper hidden" data-step-title="<?php esc_html_e( 'Exclude users', 'wp-2fa' ); ?>">
479 <?php First_Time_Wizard_Steps::exclude_users( true ); ?>
480 <div class="wp2fa-setup-actions">
481 <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>
482 </div>
483 </div>
484
485 <?php if ( WP_Helper::is_multisite() ) : ?>
486 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Exclude sites', 'wp-2fa' ); ?>">
487 <?php First_Time_Wizard_Steps::excluded_network_sites( true ); ?>
488 <div class="wp2fa-setup-actions">
489 <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>
490 </div>
491 </div>
492 <?php endif; ?>
493
494 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Grace period', 'wp-2fa' ); ?>">
495 <h3><?php esc_html_e( 'How long should the grace period for your users be?', 'wp-2fa' ); ?></h3>
496 <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>
497 <?php First_Time_Wizard_Steps::grace_period( true ); ?>
498 <div class="wp2fa-setup-actions">
499 <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>
500 </div>
501 </div>
502
503 </form>
504 <?php
505 }
506
507 /**
508 * Step Save: `Choose Method`
509 *
510 * @SuppressWarnings(PHPMD.ExitExpression)
511 */
512 private static function wp_2fa_step_global_2fa_methods_save() {
513 // Check nonce.
514 check_admin_referer( 'wp2fa-step-choose-method' );
515
516 $input = ( isset( $_POST[ WP_2FA_POLICY_SETTINGS_NAME ] ) ) ? wp_unslash( $_POST[ WP_2FA_POLICY_SETTINGS_NAME ] ) : array(); // phpcs:ignore
517
518 if ( ! WP_Helper::is_multisite() ) {
519 unregister_setting(
520 WP_2FA_POLICY_SETTINGS_NAME,
521 WP_2FA_POLICY_SETTINGS_NAME
522 );
523 }
524 $settings_page = new Settings_Page_Policies();
525 $sanitized_settings = $settings_page->validate_and_sanitize( $input, 'setup_wizard' );
526 WP2FA::update_plugin_settings( $sanitized_settings );
527
528 wp_safe_redirect( esc_url_raw( self::get_next_step() ) );
529 exit();
530 }
531
532 /**
533 * Send email with fresh code, or to setup email 2fa.
534 *
535 * @param int $user_id User id we want to send the message to.
536 * @param string $nominated_email_address - The user custom address to use (name of the meta key to check for).
537 *
538 * @return bool
539 *
540 * @SuppressWarnings(PHPMD.ExitExpression)
541 */
542 public static function send_authentication_setup_email( $user_id, $nominated_email_address = 'nominated_email_address' ) {
543
544 // If we have a nonce posted, check it.
545 if ( \wp_doing_ajax() && isset( $_POST['nonce'] ) ) {
546 $nonce_check = \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['nonce'] ) ), 'wp-2fa-send-setup-email' );
547 if ( ! $nonce_check ) {
548 return false;
549 }
550 }
551
552 if ( isset( $_POST['user_id'] ) ) {
553 $user = get_userdata( intval( $_POST['user_id'] ) );
554 } else {
555 $user = get_userdata( $user_id );
556 }
557
558 // Grab email address is its provided.
559 if ( isset( $_POST['email_address'] ) ) {
560 $email = sanitize_email( \wp_unslash( $_POST['email_address'] ) );
561 } else {
562 $email = sanitize_email( $user->user_email );
563 }
564
565 if ( wp_doing_ajax() && isset( $_POST['nonce'] ) ) {
566 update_user_meta( $user->ID, WP_2FA_PREFIX . 'nominated_email_address', $email );
567 }
568
569 $enabled_email_address = '';
570 if ( ! empty( $nominated_email_address ) ) {
571 $enabled_email_address = get_user_meta( $user->ID, WP_2FA_PREFIX . $nominated_email_address, true );
572 }
573
574 // Generate a token and setup email.
575 $token = Authentication::generate_token( $user->ID );
576
577
578 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_subject' ), $user->ID ) );
579 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_body' ), $user->ID, $token ) );
580
581 if ( ! empty( $enabled_email_address ) ) {
582 $email_address = $enabled_email_address;
583 } else {
584 $email_address = $user->user_email;
585 }
586
587 return Settings_Page::send_email( $email_address, $subject, $message );
588 }
589
590 /**
591 * Send email with fresh code, or to setup email 2fa.
592 *
593 * @param int $user_id User id we want to send the message to.
594 * @param string $nominated_email_address - The user custom address to use (name of the meta key to check for).
595 *
596 * @return bool
597 *
598 * @SuppressWarnings(PHPMD.ExitExpression)
599 */
600 public static function send_backup_codes_email( $user_id, $nominated_email_address = 'nominated_email_address' ) {
601
602 // If we have a nonce posted, check it.
603 if ( \wp_doing_ajax() && isset( $_POST['nonce'] ) ) {
604 $nonce_check = \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['nonce'] ) ), 'wp-2fa-send-backup-codes-email-nonce' );
605 if ( ! $nonce_check ) {
606 return false;
607 }
608 }
609
610 if ( isset( $_POST['user_id'] ) ) {
611 $user = get_userdata( intval( $_POST['user_id'] ) );
612 } else {
613 $user = get_userdata( $user_id );
614 }
615
616 // Grab email address is its provided.
617 if ( isset( $_POST['email_address'] ) ) {
618 $email = sanitize_email( \wp_unslash( $_POST['email_address'] ) );
619 } else {
620 $email = sanitize_email( $user->user_email );
621 }
622
623 $enabled_email_address = '';
624 if ( ! empty( $nominated_email_address ) ) {
625 $enabled_email_address = get_user_meta( $user->ID, WP_2FA_PREFIX . $nominated_email_address, true );
626 }
627
628 $codes = substr( str_replace( '\\n', '<br>', \sanitize_text_field( \wp_unslash( $_POST['codes'] ) ) ), 1, -1 );
629
630 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_backup_codes_email_subject' ), $user->ID ) );
631 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_backup_codes_email_body' ), $user->ID ) );
632
633 $final_output = str_replace( '{backup_codes}', $codes, $message );
634
635 if ( ! empty( $enabled_email_address ) ) {
636 $email_address = $enabled_email_address;
637 } else {
638 $email_address = $user->user_email;
639 }
640
641 return Settings_Page::send_email( $email_address, $subject, $final_output );
642 }
643
644
645 /**
646 * Send email to setup authentication
647 */
648 public static function regenerate_authentication_key() {
649 // Grab current user.
650 $user = wp_get_current_user();
651
652 $key = Authentication::generate_key();
653
654 $site_name = site_url();
655 $site_name = trim( str_replace( array( 'http://', 'https://' ), '', $site_name ), '/' );
656
657 /**
658 * Changing the title of the login screen for the TOTP method.
659 *
660 * @param string $title - The default title.
661 * @param \WP_User $user - The WP user.
662 *
663 * @since 2.0.0
664 */
665 $totp_title = apply_filters( WP_2FA_PREFIX . 'totp_title', $site_name . ':' . $user->user_login, $user );
666 $new_qr = Authentication::get_google_qr_code( $totp_title, $key, $site_name );
667
668 wp_send_json_success(
669 array(
670 'key' => Authentication::decrypt_key_if_needed( $key ),
671 'qr' => $new_qr,
672 )
673 );
674 }
675
676 /**
677 * 3rd Party plugins
678 *
679 * @param array $wizard_steps - Array with the current wizard steps.
680 *
681 * @return array
682 */
683 public static function wp_2fa_add_intro_step( $wizard_steps ) {
684 $new_wizard_steps = array(
685 'test' => array(
686 'name' => __( 'Welcome to WP 2FA', 'wp-2fa' ),
687 'content' => array( __CLASS__, 'introduction_step' ),
688 'save' => array( __CLASS__, 'introduction_step_save' ),
689 'wizard_type' => 'welcome_wizard',
690 ),
691 );
692
693 // combine the two arrays.
694 $wizard_steps = $new_wizard_steps + $wizard_steps;
695
696 return $wizard_steps;
697 }
698
699 /**
700 * Shows introduction step of the wizard
701 *
702 * @return void
703 */
704 private static function introduction_step() {
705 Wizard_Steps::introduction_step();
706 }
707
708 /**
709 * Step Save: `Addons`
710 *
711 * @SuppressWarnings(PHPMD.ExitExpression)
712 */
713 private static function introduction_step_save() {
714 // Check nonce.
715 check_admin_referer( 'wp2fa-step-addon' );
716
717 wp_safe_redirect( esc_url_raw( self::get_next_step() ) );
718 exit();
719 }
720 }
721 }
722