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