PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.5.0
WP 2FA – Two-factor authentication for WordPress v2.5.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-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 5 years ago
class-setup-wizard.php
731 lines
1 <?php
2 /**
3 * Setup wizard rendering class.
4 *
5 * @package wp2fa
6 * @subpackage setup
7 * @copyright %%YEAR%% 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 as Core;
15 use \WP2FA\WP2FA as WP2FA;
16 use WP2FA\Admin\Helpers\WP_Helper;
17 use WP2FA\Admin\Views\Wizard_Steps;
18 use WP2FA\Admin\Helpers\User_Helper;
19 use WP2FA\Admin\Controllers\Settings;
20 use \WP2FA\Utils\User_Utils as User_Utils;
21 use WP2FA\Admin\Views\First_Time_Wizard_Steps;
22 use \WP2FA\Admin\Settings_Page as Settings_Page;
23 use WP2FA\Utils\Settings_Utils as Settings_Utils;
24 use \WP2FA\Utils\Generate_Modal as Generate_Modal;
25 use \WP2FA\Admin\SettingsPages\Settings_Page_Policies;
26 use \WP2FA\Authenticator\Authentication as Authentication;
27
28 /**
29 * Setup_Wizard class for the wizard steps setup
30 *
31 * @since 2.4.0
32 */
33 if ( ! class_exists( '\WP2FA\Admin\Setup_Wizard' ) ) {
34 /**
35 * Our class for creating a step by step wizard for easy configuration.
36 */
37 class Setup_Wizard {
38
39 /**
40 * Wizard Steps
41 *
42 * @var array
43 */
44 private static $wizard_steps;
45
46 /**
47 * Current Step
48 *
49 * @var string
50 */
51 private static $current_step;
52
53 /**
54 * Add setup admin page. This is empty on purpose.
55 */
56 public static function admin_menus() {
57 add_dashboard_page( '', '', 'read', 'wp-2fa-setup', '' );
58 }
59
60 /**
61 * Adding menus for multisite install
62 *
63 * @return void
64 *
65 * @since 2.2.0
66 */
67 public static function network_admin_menus() {
68 add_dashboard_page( 'index.php', '', 'read', 'wp-2fa-setup', '' );
69 }
70
71 /**
72 * Setup Page Start.
73 *
74 * @SuppressWarnings(PHPMD.ExitExpression)
75 */
76 public static function setup_page() {
77
78 // Get page argument from $_GET array.
79 $page = ( isset( $_GET['page'] ) ) ? \sanitize_text_field( \wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore
80 if ( empty( $page ) || 'wp-2fa-setup' !== $page ) {
81 return;
82 }
83
84 // Clear out any old notices.
85 $user = wp_get_current_user();
86
87 // First lets check if any options have been saved.
88 $settings_saved = true;
89 $settings = WP2FA::get_wp2fa_setting();
90 if ( empty( $settings ) || ! isset( $settings ) ) {
91 $settings_saved = false;
92 }
93
94 /**
95 * Wizard Steps.
96 */
97 $get_array = filter_input_array( INPUT_GET );
98 if ( isset( $get_array['wizard_type'] ) ) {
99 $wizard_type = sanitize_text_field( $get_array['wizard_type'] );
100 } else {
101 $wizard_type = 'default';
102 }
103
104 $is_user_forced_to_setup = User_Helper::get_user_enforced_instantly( $user );
105 if ( ! empty( $is_user_forced_to_setup ) ) {
106 add_filter( 'wp_2fa_wizard_default_steps', array( __CLASS__, 'wp_2fa_add_intro_step' ) );
107 }
108
109 $user_type = User_Utils::determine_user_2fa_status( $user );
110
111 $wizard_steps = array(
112 'welcome' => array(
113 'name' => esc_html__( 'Welcome', 'wp-2fa' ),
114 'content' => array( __CLASS__, 'wp_2fa_step_welcome' ),
115 'wizard_type' => 'welcome_wizard',
116 ),
117 'settings_configuration' => array(
118 'name' => esc_html__( 'Configure 2FA methods & Policies', 'wp-2fa' ),
119 'content' => array( __CLASS__, 'wp_2fa_step_global_2fa_methods' ),
120 'save' => array( __CLASS__, 'wp_2fa_step_global_2fa_methods_save' ),
121 'wizard_type' => 'welcome_wizard',
122 ),
123 'finish' => array(
124 'name' => esc_html__( 'Setup Finish', 'wp-2fa' ),
125 'content' => array( __CLASS__, 'wp_2fa_step_finish' ),
126 'save' => array( __CLASS__, 'wp_2fa_step_finish_save' ),
127 'wizard_type' => 'welcome_wizard',
128 ),
129 );
130
131 // Admin user setting up fresh install of 2FA plugin.
132 if ( in_array( 'can_manage_options', $user_type, true ) && ! $settings_saved ) {
133 unset( $wizard_steps['user_choose_2fa_method'] );
134 unset( $wizard_steps['reconfigure_method'] );
135 }
136
137 // We will use this setting to determine if defaults have already been saved to the DB.
138 $have_defaults_been_applied = Settings_Utils::get_option( 'default_settings_applied', false );
139 // If we have settings, but they are the defaults, then we want to consider the settings to be unsaved at this point.
140 if ( in_array( 'can_manage_options', $user_type, true ) && $settings_saved && $have_defaults_been_applied ) {
141 $settings_saved = false;
142 }
143
144 // Ensure user has minimum capabitlies needed to be here.
145 if ( in_array( 'can_read', $user_type, true ) && $settings_saved ) {
146
147 switch ( $wizard_type ) {
148 case 'user_2fa_config':
149 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( array( 'user_choose_2fa_method', 'setup_method', 'finish', 'backup_codes' ) ) );
150 break;
151
152 case 'backup_codes_config':
153 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( array( 'backup_codes' ) ) );
154 break;
155
156 case 'user_reconfigure_config':
157 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( array( 'reconfigure_method' ) ) );
158 break;
159
160 default:
161 $wizard_steps = array_intersect_key( $wizard_steps, array_flip( array( 'choose_2fa_method', 'setup_method', 'finish', 'backup_codes', 'reconfigure_method' ) ) );
162 }
163
164 // Remove 1st step if only one method is available.
165 if ( empty( WP2FA::get_wp2fa_setting( 'enable_totp' ) ) || empty( WP2FA::get_wp2fa_setting( 'enable_email' ) ) ) {
166 unset( $wizard_steps['choose_2fa_method'] );
167 }
168
169 // If the user has codes setup already, no need to add the slide.
170 if ( ! in_array( 'user_needs_to_setup_backup_codes', $user_type, true ) && 'backup_codes_config' !== $wizard_type ) {
171 unset( $wizard_steps['backup_codes'] );
172 }
173 }
174
175 /**
176 * Filter: `Wizard Default Steps`
177 *
178 * WSAL filter to filter wizard steps before they are displayed.
179 *
180 * @param array $wizard_steps – Wizard Steps.
181 */
182 self::$wizard_steps = apply_filters( WP_2FA_PREFIX . 'wizard_default_steps', $wizard_steps );
183
184 // Set current step.
185 $current_step = ( isset( $_GET['current-step'] ) ) ? \sanitize_text_field( \wp_unslash( $_GET['current-step'] ) ) : ''; // phpcs:ignore
186 self::$current_step = ! empty( $current_step ) ? $current_step : current( array_keys( self::$wizard_steps ) );
187
188 if ( 'backup_codes' === self::$current_step && ! Settings_Page::are_backup_codes_enabled( User_Helper::get_user_role( $user ) ) ) {
189
190 $redirect_to_finish = add_query_arg(
191 array(
192 'current-step' => 'finish',
193 'all-set' => 1,
194 )
195 );
196 wp_safe_redirect( esc_url_raw( $redirect_to_finish ) );
197 }
198
199 /**
200 * Enqueue Scripts.
201 */
202 wp_enqueue_style(
203 'wp_2fa_setup_wizard',
204 Core\style_url( 'setup-wizard', 'admin' ),
205 array( 'select2' ),
206 WP_2FA_VERSION
207 );
208
209 wp_enqueue_style(
210 'wp_2fa_admin-style',
211 Core\style_url( 'admin-style', 'admin' ),
212 array(),
213 WP_2FA_VERSION
214 );
215
216 \WP2FA\Core\enqueue_select2_scripts();
217
218 if ( \WP2FA\Admin\Helpers\WP_Helper::is_multisite() ) {
219 \WP2FA\Core\enqueue_multi_select_scripts();
220 }
221
222 wp_enqueue_script(
223 'wp_2fa_admin',
224 Core\script_url( 'admin', 'admin' ),
225 array( 'jquery-ui-widget', 'jquery-ui-core', 'jquery-ui-autocomplete', 'select2' ),
226 WP_2FA_VERSION,
227 true
228 );
229
230 wp_enqueue_script(
231 'wp_2fa_micromodal',
232 Core\script_url( 'micromodal', 'admin', 'select2' ),
233 array(),
234 WP_2FA_VERSION,
235 true
236 );
237
238 // Data array.
239 $data_array = array(
240 'ajaxURL' => admin_url( 'admin-ajax.php' ),
241 'roles' => WP2FA::wp_2fa_get_roles(),
242 'nonce' => wp_create_nonce( 'wp-2fa-settings-nonce' ),
243 'invalidEmail ' => esc_html__( 'Please use a valid email address', 'wp-2fa' ),
244 'backupCodesSent' => esc_html__( 'Backup codes sent', '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://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>
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 User_Helper::remove_user_needs_to_reconfigure_2fa( User_Helper::get_user_object() );
435 Wizard_Steps::congratulations_step( true );
436 }
437
438 /**
439 * Step Save: `Finish`
440 *
441 * @SuppressWarnings(PHPMD.ExitExpression)
442 */
443 private static function wp_2fa_step_finish_save() {
444 // Verify nonce.
445 check_admin_referer( 'wp2fa-step-finish' );
446 wp_safe_redirect( esc_url_raw( self::get_next_step() ) );
447 exit();
448 }
449
450 /**
451 * Step View: `Choose Methods`
452 */
453 private static function wp_2fa_step_global_2fa_methods() {
454 ?>
455 <form method="post" class="wp2fa-setup-form wp2fa-form-styles" autocomplete="off">
456 <?php wp_nonce_field( 'wp2fa-step-choose-method' ); ?>
457 <div class="step-setting-wrapper active" data-step-title="<?php esc_html_e( '2FA methods', 'wp-2fa' ); ?>">
458 <?php First_Time_Wizard_Steps::select_method( true ); ?>
459 <div class="wp2fa-setup-actions">
460 <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>
461 </div>
462 </div>
463 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Alternative methods', 'wp-2fa' ); ?>">
464 <?php First_Time_Wizard_Steps::backup_method( true ); ?>
465 <div class="wp2fa-setup-actions">
466 <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>
467 </div>
468 </div>
469 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( '2FA policy', 'wp-2fa' ); ?>">
470 <?php First_Time_Wizard_Steps::enforcement_policy( true ); ?>
471 <div class="wp2fa-setup-actions">
472 <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>
473 <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>
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', $is_reset_protection = false ) {
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 if ( $is_reset_protection ) {
577 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'reset_password_code_email_subject' ), $user->ID ) );
578 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'reset_password_code_email_body' ), $user->ID, $token ) );
579 } else if ( wp_doing_ajax() && isset( $_POST['nonce'] ) ) {
580 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_subject' ), $user->ID ) );
581 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_setup_email_body' ), $user->ID, $token ) );
582 } else {
583 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_subject' ), $user->ID ) );
584 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'login_code_email_body' ), $user->ID, $token ) );
585 }
586
587 if ( ! empty( $enabled_email_address ) ) {
588 $email_address = $enabled_email_address;
589 } else {
590 $email_address = $user->user_email;
591 }
592
593 return Settings_Page::send_email( $email_address, $subject, $message );
594 }
595
596 /**
597 * Send email with fresh code, or to setup email 2fa.
598 *
599 * @param int $user_id User id we want to send the message to.
600 * @param string $nominated_email_address - The user custom address to use (name of the meta key to check for).
601 *
602 * @return bool
603 *
604 * @SuppressWarnings(PHPMD.ExitExpression)
605 */
606 public static function send_backup_codes_email( $user_id, $nominated_email_address = 'nominated_email_address' ) {
607
608 // If we have a nonce posted, check it.
609 if ( \wp_doing_ajax() && isset( $_POST['nonce'] ) ) {
610 $nonce_check = \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['nonce'] ) ), 'wp-2fa-send-backup-codes-email-nonce' );
611 if ( ! $nonce_check ) {
612 return false;
613 }
614 }
615
616 if ( isset( $_POST['user_id'] ) ) {
617 $user = get_userdata( intval( $_POST['user_id'] ) );
618 } else {
619 $user = get_userdata( $user_id );
620 }
621
622 // Grab email address is its provided.
623 if ( isset( $_POST['email_address'] ) ) {
624 $email = sanitize_email( \wp_unslash( $_POST['email_address'] ) );
625 } else {
626 $email = sanitize_email( $user->user_email );
627 }
628
629 $enabled_email_address = '';
630 if ( ! empty( $nominated_email_address ) ) {
631 $enabled_email_address = get_user_meta( $user->ID, WP_2FA_PREFIX . $nominated_email_address, true );
632 }
633
634 $codes = substr( str_replace( '\\n', '<br>', \sanitize_text_field( \wp_unslash( $_POST['codes'] ) ) ), 1, -1 );
635
636 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_backup_codes_email_subject' ), $user->ID ) );
637 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_backup_codes_email_body' ), $user->ID ) );
638
639 $final_output = str_replace( '{backup_codes}', $codes, $message );
640
641 if ( ! empty( $enabled_email_address ) ) {
642 $email_address = $enabled_email_address;
643 } else {
644 $email_address = $user->user_email;
645 }
646
647 return Settings_Page::send_email( $email_address, $subject, $final_output );
648 }
649
650 /**
651 * Regenerates the TOTP key for the user
652 *
653 * @return void - JSON - object with "key" - stores the new key and "qr" - stores the new QR code.
654 *
655 * @since 2.5.0
656 */
657 public static function regenerate_authentication_key() {
658 // Grab current user.
659 $user = wp_get_current_user();
660
661 $key = Authentication::generate_key();
662
663 $site_name = site_url();
664 $site_name = trim( str_replace( array( 'http://', 'https://' ), '', $site_name ), '/' );
665
666 /**
667 * Changing the title of the login screen for the TOTP method.
668 *
669 * @param string $title - The default title.
670 * @param \WP_User $user - The WP user.
671 *
672 * @since 2.0.0
673 */
674 $totp_title = apply_filters( WP_2FA_PREFIX . 'totp_title', $site_name . ':' . $user->user_login, $user );
675 $new_qr = Authentication::get_google_qr_code( $totp_title, $key, $site_name );
676
677 wp_send_json_success(
678 array(
679 'key' => Authentication::decrypt_key_if_needed( $key ),
680 'qr' => $new_qr,
681 )
682 );
683 }
684
685 /**
686 * 3rd Party plugins
687 *
688 * @param array $wizard_steps - Array with the current wizard steps.
689 *
690 * @return array
691 */
692 public static function wp_2fa_add_intro_step( $wizard_steps ) {
693 $new_wizard_steps = array(
694 'test' => array(
695 'name' => __( 'Welcome to WP 2FA', 'wp-2fa' ),
696 'content' => array( __CLASS__, 'introduction_step' ),
697 'save' => array( __CLASS__, 'introduction_step_save' ),
698 'wizard_type' => 'welcome_wizard',
699 ),
700 );
701
702 // combine the two arrays.
703 $wizard_steps = $new_wizard_steps + $wizard_steps;
704
705 return $wizard_steps;
706 }
707
708 /**
709 * Shows introduction step of the wizard
710 *
711 * @return void
712 */
713 private static function introduction_step() {
714 Wizard_Steps::introduction_step();
715 }
716
717 /**
718 * Step Save: `Addons`
719 *
720 * @SuppressWarnings(PHPMD.ExitExpression)
721 */
722 private static function introduction_step_save() {
723 // Check nonce.
724 check_admin_referer( 'wp2fa-step-addon' );
725
726 wp_safe_redirect( esc_url_raw( self::get_next_step() ) );
727 exit();
728 }
729 }
730 }
731