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 / Views / class-wizard-steps.php
wp-2fa / includes / classes / Admin / Views Last commit date
class-first-time-wizard-steps.php 3 years ago class-settings-page-render.php 3 years ago class-wizard-steps.php 3 years ago
class-wizard-steps.php
876 lines
1 <?php
2 /**
3 * Settings page render class.
4 *
5 * @package wp2fa
6 * @subpackage views
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\Views;
13
14 use WP2FA\WP2FA;
15 use WP2FA\Admin\User;
16 use WP2FA\Utils\User_Utils;
17 use WP2FA\Admin\Helpers\User_Helper;
18 use WP2FA\Admin\Controllers\Settings;
19 use WP2FA\Authenticator\Authentication;
20
21 defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
22
23 /**
24 * WP2FA Wizard Settings view controller
25 *
26 * @since 1.7
27 */
28 class Wizard_Steps {
29
30 /**
31 * Holds the current user
32 *
33 * @since 1.7
34 *
35 * @var \WP2FA\Admin\User
36 */
37 private static $user = null;
38
39 /**
40 * Is the totp method enabled
41 *
42 * @since 1.7
43 *
44 * @var bool
45 */
46 private static $totp_enabled = null;
47
48 /**
49 * Is the mail enabled
50 *
51 * @since 1.7
52 *
53 * @var bool
54 */
55 private static $email_enabled = null;
56
57 /**
58 * Holds the nonce for json calls
59 *
60 * @since 1.7
61 *
62 * @var string
63 */
64 private static $json_nonce = null;
65
66 /**
67 * Holds the url to which to redirect the user after the setup is finished
68 *
69 * @var string
70 *
71 * @since 2.0.0
72 */
73 private static $redirect_url = null;
74
75 /**
76 * Introduction step form
77 *
78 * @since 1.7
79 *
80 * @return void
81 */
82 public static function optional_user_welcome_step() {
83 ?>
84 <div class="wizard-step active">
85 <div class="mb-20">
86 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'welcome', true ) ); ?>
87 </div>
88
89 <div class="wp2fa-setup-actions">
90 <a href="#" class="button wp-2fa-button-primary button-primary" data-name="next_step_setting_modal_wizard" data-next-step="choose-2fa-method"><?php esc_html_e( 'Next Step', 'wp-2fa' ); ?></a>
91 <button class="wp-2fa-button-secondary button button-secondary wp-2fa-button-secondary" data-close-2fa-modal aria-label="Close this dialog window"><?php esc_html_e( 'Cancel', 'wp-2fa' ); ?></button>
92 </div>
93 </div>
94 <?php
95 }
96
97 /**
98 * Introduction step form
99 *
100 * @since 1.7
101 *
102 * @return void
103 */
104 public static function introduction_step() {
105 ?>
106 <form method="post" class="wp2fa-setup-form">
107 <?php wp_nonce_field( 'wp2fa-step-addon' ); ?>
108 <div class="mb-20">
109 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( '2fa_required_intro', true ) ); ?>
110 </div>
111
112 <div class="wp2fa-setup-actions">
113 <button class="button button-primary wp-2fa-button-primary"
114 type="submit"
115 name="save_step"
116 value="<?php esc_attr_e( 'Next', 'wp-2fa' ); ?>">
117 <?php esc_html_e( 'Next', 'wp-2fa' ); ?>
118 </button>
119 </div>
120 </form>
121 <?php
122 }
123
124 /**
125 * Welcome step of the wizard
126 *
127 * @since 1.7
128 *
129 * @param string $next_step - url of the next step.
130 *
131 * @return void
132 */
133 public static function welcome_step( $next_step ) {
134 $redirect = Settings::get_settings_page_link();
135
136 ?>
137 <h3><?php esc_html_e( 'Let us help you get started', 'wp-2fa' ); ?></h3>
138 <p><?php esc_html_e( 'Thank you for installing the WP 2FA plugin. This quick wizard will assist you with configuring the plugin and the two-factor authentication (2FA) settings for your user and the users on this website.', 'wp-2fa' ); ?></p>
139
140 <div class="wp2fa-setup-actions">
141 <a class="button button-primary"
142 href="<?php echo esc_url( $next_step ); ?>">
143 <?php esc_html_e( 'Let’s get started!', 'wp-2fa' ); ?>
144 </a>
145 <a class="button button-secondary wp-2fa-button-secondary first-time-wizard"
146 href="<?php echo esc_url( $redirect ); ?>">
147 <?php esc_html_e( 'Skip Wizard - I know how to do this', 'wp-2fa' ); ?>
148 </a>
149 </div>
150 <?php
151 }
152
153 /**
154 * Shows the initial totp setup options based on enabled methods
155 *
156 * @since 1.7
157 *
158 * @return void
159 */
160 public static function totp_option() {
161 if ( self::is_totp_enabled() ) {
162 ?>
163 <div class="option-pill">
164 <label for="basic">
165 <input id="basic" name="wp_2fa_enabled_methods" type="radio" value="totp" checked>
166 <?php esc_html_e( 'One-time code via 2FA app', 'wp-2fa' ); ?><span class="wizard-tooltip" data-tooltip-content="data-totp-tooltip-content-wrapper">i</span>
167 </label>
168 <?php
169 echo '<p class="description tooltip-content-wrapper" data-totp-tooltip-content-wrapper>';
170 printf(
171 /* translators: link to the knowledge base website */
172 esc_html__( 'Refer to the %s for more information on how to setup these apps and which apps are supported.', 'wp-2fa' ),
173 '<a href="https://wp2fa.io/support/kb/configuring-2fa-apps/" target="_blank">' . esc_html__( 'guide on how to set up 2FA apps', 'wp-2fa' ) . '</a>'
174 );
175 echo '</p>';
176 ?>
177 </div>
178 <?php
179 }
180 }
181
182 /**
183 * Shows the initial email setup option based on enabled methods
184 *
185 * @since 1.7
186 *
187 * @return void
188 */
189 public static function email_option() {
190 if ( self::is_mail_enabled() ) {
191 ?>
192 <div class="option-pill">
193 <label for="geek">
194 <input id="geek" name="wp_2fa_enabled_methods" type="radio" value="email">
195 <?php esc_html_e( 'One-time code via email', 'wp-2fa' ); ?>
196 </label>
197 </div>
198 <?php
199 }
200 }
201
202
203 /**
204 * Shows the option to reconfigure email (if applicable)
205 *
206 * @since 1.7
207 *
208 * @return void
209 */
210 public static function totp_re_configure() {
211
212 if ( ! self::is_totp_enabled() ) {
213 return;
214 }
215
216 $nonce = self::json_nonce();
217
218 ?>
219 <div class="option-pill">
220 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'totp_reconfigure_intro', true ) ); ?>
221 <div class="wp2fa-setup-actions">
222 <a href="#" class="button button-primary wp-2fa-button-primary" data-name="next_step_setting_modal_wizard" data-trigger-reset-key data-nonce="<?php echo esc_attr( $nonce ); ?>" data-user-id="<?php echo esc_attr( self::get_user()->get_2fa_wp_user()->ID ); ?>" data-next-step="2fa-wizard-totp"><?php esc_html_e( 'Reset Key', 'wp-2fa' ); ?></a>
223 </div>
224 </div>
225 <?php
226 }
227
228 /**
229 * Shows the option for email method reconfiguring (if applicable)
230 *
231 * @since 1.7
232 *
233 * @return void
234 */
235 public static function email_re_configure() {
236
237 if ( ! self::is_mail_enabled() ) {
238 return;
239 }
240
241 $setupnonce = wp_create_nonce( 'wp-2fa-send-setup-email' );
242 ?>
243 <div class="option-pill">
244 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'hotp_reconfigure_intro', true ) ); ?>
245 <div class="wp2fa-setup-actions">
246 <a class="button button-primary wp-2fa-button-primary" data-name="next_step_setting_modal_wizard" value="<?php esc_attr_e( 'I\'m Ready', 'wp-2fa' ); ?>" data-user-id="<?php echo esc_attr( self::get_user()->get_2fa_wp_user()->ID ); ?>" data-nonce="<?php echo esc_attr( $setupnonce ); ?>" data-next-step="2fa-wizard-email"><?php esc_html_e( 'Change email address', 'wp-2fa' ); ?></a>
247 </div>
248 </div>
249 <?php
250 }
251
252 /**
253 * Reconfigures the totp form
254 *
255 * @since 1.7
256 *
257 * @return void
258 */
259 public static function totp_configure() {
260
261 if ( ! self::is_totp_enabled() ) {
262 return;
263 }
264 /**
265 * Active on modal, additional attribute is required on standard HTML (check below)
266 */
267 $add_step_attributes = 'active';
268
269 /**
270 * Closing div for extra modal wrappers see lines above
271 */
272 $close_div = '';
273
274 $qr_code = '<img class="qr-code" src="' . ( self::get_qr_code() ) . '" id="wp-2fa-totp-qrcode" />';
275 $open30_wrapper = '
276 <div class="mb-30 clear-both">
277 ';
278 $open60_wrapper = '
279 <div class="modal-60">
280 ';
281 $open40_wrapper = '
282 <div class="modal-40">
283 ';
284 $close_div = '
285 </div>
286 ';
287 $validate_nonce = wp_create_nonce( 'wp-2fa-validate-authcode' );
288
289 ?>
290 <div class="step-setting-wrapper <?php echo $add_step_attributes; // phpcs:ignore ?>">
291 <div class="mb-20">
292 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'method_help_totp_intro', true ) ); ?>
293 </div>
294 <?php echo $open30_wrapper . $open40_wrapper; // phpcs:ignore ?>
295
296 <div class="qr-code-wrapper">
297 <?php echo $qr_code; // phpcs:ignore ?>
298 </div>
299 <?php
300 echo $close_div; // phpcs:ignore
301 echo $open60_wrapper; // phpcs:ignore
302 ?>
303
304 <div class="radio-cells option-pill mb-0">
305 <ol class="wizard-custom-counter">
306 <li><?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'method_help_totp_step_1', true ) ); ?><?php if ( ! empty( WP2FA::get_wp2fa_white_label_setting( 'show_help_text' ) ) ) { ?><span class="wizard-tooltip" data-tooltip-content="data-totp-setup-tooltip-content-wrapper">i</span><?php } ?></li>
307 <li><?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'method_help_totp_step_2', true ) ); ?>
308 <div class="app-key-wrapper">
309 <input type="text" id="app-key-input" readonly value="<?php echo esc_html( self::get_user()->get_totp_decrypted() ); ?>" class="app-key">
310 <?php
311 if ( is_ssl() ) {
312 ?>
313 <span class="click-to-copy"><?php esc_html_e( 'COPY', 'wp-2fa' ); ?></span>
314 <?php } ?>
315 </div>
316 </li>
317 <li><?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'method_help_totp_step_3', true ) ); ?></li>
318 </ol>
319 </div>
320 <?php
321 echo $close_div; // phpcs:ignore
322 echo $close_div; // phpcs:ignore
323 ?>
324 <?php if ( ! empty( WP2FA::get_wp2fa_white_label_setting( 'show_help_text' ) ) ) : ?>
325 <div class="tooltip-content-wrapper" data-totp-setup-tooltip-content-wrapper>
326 <p class="description"><?php esc_html_e( 'Click on the icon of the app that you are using for a detailed guide on how to set it up.', 'wp-2fa' ); ?></p>
327 <div class="apps-wrapper">
328 <?php foreach ( Authentication::get_apps() as $app ) { ?>
329 <a href="https://www.wpwhitesecurity.com/support/kb/configuring-2fa-apps/#<?php echo $app['hash']; ?>" target="_blank" class="app-logo"><img src="<?php echo esc_url( WP_2FA_URL . 'dist/images/' . $app['logo'] ); // phpcs:ignore ?>"></a>
330 <?php } ?>
331 </div>
332 </div>
333 <?php endif; ?>
334 <div class="wp2fa-setup-actions">
335 <button class="button wp-2fa-button-primary" name="next_step_setting" value="<?php esc_attr_e( 'I\'m Ready', 'wp-2fa' ); ?>" type="button"><?php esc_html_e( 'I\'m Ready', 'wp-2fa' ); ?></button>
336 </div>
337 </div>
338 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Verify configuration', 'wp-2fa' ); ?>">
339 <div class="mb-20">
340 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'method_verification_totp_pre', true ) ); ?>
341 </div>
342 <fieldset>
343 <label for="2fa-totp-authcode">
344 <?php esc_html_e( 'Authentication Code', 'wp-2fa' ); ?>
345 <input type="tel" name="wp-2fa-totp-authcode" id="wp-2fa-totp-authcode" class="input" value="" size="20" pattern="[0-9]*"/>
346 </label>
347 <div class="verification-response"></div>
348 </fieldset>
349 <input type="hidden" name="wp-2fa-totp-key" value="<?php echo esc_attr( self::get_user()->get_totp_decrypted() ); ?>" />
350
351 <a href="#" class="modal__btn button button-primary wp-2fa-button-primary" data-validate-authcode-ajax data-nonce="<?php echo esc_attr( $validate_nonce ); ?>"><?php esc_html_e( 'Validate & Save', 'wp-2fa' ); ?></a>
352 <button class="modal__btn wp-2fa-button-secondary button button-secondary wp-2fa-button-secondary" data-close-2fa-modal aria-label="Close this dialog window"><?php esc_html_e( 'Cancel', 'wp-2fa' ); ?></button>
353 </div>
354
355 <?php
356 }
357
358 /**
359 * Reconfigures email form
360 *
361 * @since 1.7
362 *
363 * @return void
364 */
365 public static function email_configure() {
366
367 if ( ! self::is_mail_enabled() ) {
368 return;
369 }
370
371 $setupnonce = wp_create_nonce( 'wp-2fa-send-setup-email' );
372
373 $validate_nonce = wp_create_nonce( 'wp-2fa-validate-authcode' );
374 ?>
375 <div class="step-setting-wrapper active">
376 <div class="mb-20">
377 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'method_help_hotp_intro', true ) ); ?>
378 </div>
379 <fieldset class="radio-cells">
380 <div class="option-pill">
381 <label for="use_wp_email">
382 <input type="radio" name="wp_2fa_email_address" id="use_wp_email" value="<?php echo esc_attr( self::get_user()->get_2fa_wp_user()->user_email ); ?>" checked>
383 <span><?php esc_html_e( 'Use my user email (', 'wp-2fa' ); ?><small><?php echo esc_attr( self::get_user()->get_2fa_wp_user()->user_email ); ?></small><?php esc_html_e( ')', 'wp-2fa' ); ?></span>
384 </label>
385 </div>
386 <?php
387 if ( Settings::get_role_or_default_setting( 'specify-email_hotp', self::get_user()->get_2fa_wp_user() ) ) {
388 ?>
389 <div class="option-pill">
390 <label for="use_custom_email">
391 <input type="radio" name="wp_2fa_email_address" id="use_custom_email" value="use_custom_email">
392 <span><?php esc_html_e( 'Use a different email address:', 'wp-2fa' ); ?></span>
393 <?php esc_html_e( 'Email address', 'wp-2fa' ); ?>
394 <input type="email" name="custom-email-address" id="custom-email-address" class="input" value=""/>
395 </label>
396 </div>
397 <?php
398 }
399 ?>
400 </fieldset>
401 <p class="description"><?php esc_html_e( 'To complete the 2FA configuration you will be sent a one-time code over email, therefore you should have access to the mailbox of this email address. If you do not receive the email with the one-time code please check your spam folder and contact your administrator.', 'wp-2fa' ); ?></p><br>
402
403 <?php
404 echo sprintf( '<b>%1$1s</b> %2$1s %3$1s',
405 esc_html__( 'IMPORTANT: ', 'wp-2fa' ),
406 esc_html__( 'To ensure you always receive the one-time code whitelist the email address from which the codes are sent. This is ', 'wp-2fa' ),
407 esc_attr( self::get_user()->get_2fa_wp_user()->user_email )
408 );
409 ?>
410
411 <div class="wp2fa-setup-actions">
412 <button class="button button-primary wp-2fa-button-primary" name="next_step_setting_email_verify" value="<?php esc_attr_e( 'I\'m Ready', 'wp-2fa' ); ?>" data-trigger-setup-email data-user-id="<?php echo esc_attr( self::get_user()->get_2fa_wp_user()->ID ); ?>" data-nonce="<?php echo esc_attr( $setupnonce ); ?>" type="button"><?php esc_html_e( 'I\'m Ready', 'wp-2fa' ); ?></button>
413
414 </div>
415 </div>
416
417 <div class="step-setting-wrapper" data-step-title="<?php esc_html_e( 'Verify configuration', 'wp-2fa' ); ?>" id="2fa-wizard-email">
418 <div class="mb-20">
419 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'method_verification_hotp_pre', true ) ); ?>
420 </div>
421 <fieldset>
422 <label for="2fa-email-authcode">
423 <?php esc_html_e( 'Authentication Code', 'wp-2fa' ); ?>
424 <input type="tel" name="wp-2fa-email-authcode" id="wp-2fa-email-authcode" class="input" value="" size="20" pattern="[0-9]*"/>
425 </label>
426 <div class="verification-response"></div>
427 </fieldset>
428 <br />
429 <a href="#" class="button wp-2fa-button-primary" data-validate-authcode-ajax data-nonce="<?php echo esc_attr( $validate_nonce ); ?>"><?php esc_html_e( 'Validate & Save', 'wp-2fa' ); ?></a>
430 <a href="#" class="button wp-2fa-button-primary resend-email-code" data-trigger-setup-email data-user-id="<?php echo esc_attr( self::get_user()->get_2fa_wp_user()->ID ); ?>" data-nonce="<?php echo esc_attr( $setupnonce ); ?>">
431 <span class="resend-inner"><?php esc_html_e( 'Send me another code', 'wp-2fa' ); ?></span>
432 </a>
433 <button class="wp-2fa-button-secondary button" data-close-2fa-modal aria-label="Close this dialog window"><?php esc_html_e( 'Cancel', 'wp-2fa' ); ?></button>
434 </div>
435 <?php
436 }
437
438 /**
439 * Configure backup codes step
440 *
441 * @since 1.7
442 *
443 * @return void
444 */
445 public static function backup_codes_configure() {
446
447 $user_type = User_Utils::determine_user_2fa_status( self::get_user()->get_2fa_wp_user() );
448
449 $redirect = self::determine_redirect_url();
450
451 $nonce = self::json_nonce();
452 ?>
453 <div class="step-setting-wrapper active">
454 <?php
455 if ( in_array( 'user_needs_to_setup_backup_codes', $user_type, true ) ) {
456 ?>
457 <div class="mb-20">
458 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_intro_continue', true ) ); ?>
459 </div>
460 <?php } else { ?>
461 <div class="mb-20">
462 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_intro', true ) ); ?>
463 </div>
464 <?php } ?>
465 <div class="wp2fa-setup-actions">
466 <?php if ( in_array( 'user_needs_to_setup_backup_codes', $user_type, true ) ) { ?>
467 <button class="button button-primary wp-2fa-button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Generate backup codes', 'wp-2fa' ); ?>" data-trigger-generate-backup-codes data-nonce="<?php echo esc_attr( $nonce ); ?>">
468 <?php esc_html_e( 'Generate list of backup codes', 'wp-2fa' ); ?>
469 </button>
470 <?php
471 if ( ! empty( $redirect ) ) {
472 ?>
473 <a href="<?php echo esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary wp-2fa-button-secondary close-first-time-wizard">
474 <?php esc_html_e( 'I’ll generate them later', 'wp-2fa' ); ?>
475 </a>
476 <?php
477 } else {
478 ?>
479 <a href="#" class="button wp-2fa-button-secondary" data-close-2fa-modal value="<?php esc_attr_e( 'I’ll generate them later', 'wp-2fa' ); ?>">
480 <?php esc_html_e( 'I’ll generate them later', 'wp-2fa' ); ?>
481 </a>
482 <?php } ?>
483 <?php } else { ?>
484 <?php
485 if ( ! empty( $redirect ) ) {
486 ?>
487 <a href="<?php echo esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary close-first-time-wizard">
488 <?php esc_html_e( 'Close wizard', 'wp-2fa' ); ?>
489 </a>
490 <?php
491 } else {
492 ?>
493 <a href="#" class="button button-secondary wp-2fa-button-secondary" data-reload>
494 <?php esc_html_e( 'Close wizard', 'wp-2fa' ); ?>
495 </a>
496 <?php } ?>
497 <?php } ?>
498 </div>
499 </div>
500 <?php
501 }
502
503 /**
504 * Generate backup codes step
505 *
506 * @since 1.7
507 *
508 * @return void
509 */
510 public static function generate_backup_codes() {
511 $nonce = self::json_nonce();
512
513 ?>
514 <div class="step-setting-wrapper active" data-step-title="<?php esc_html_e( 'Generate codes', 'wp-2fa' ); ?>">
515 <div class="mb-20">
516 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_generate_intro', true ) ); ?>
517 </div>
518 <div class="wp2fa-setup-actions">
519 <button class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'Generate backup codes', 'wp-2fa' ); ?>" data-trigger-generate-backup-codes data-nonce="<?php echo esc_attr( $nonce ); ?>">
520 <?php esc_html_e( 'Generate list of backup codes', 'wp-2fa' ); ?>
521 </button>
522 <a href="#" class="button button-secondary wp-2fa-button-secondary" value="<?php esc_attr_e( 'I’ll generate them later', 'wp-2fa' ); ?>" data-close-2fa-modal="">
523 <?php esc_html_e( 'I’ll generate them later', 'wp-2fa' ); ?>
524 </a>
525 </div>
526 </div>
527
528 <?php
529 }
530
531 /**
532 * Creates link for generating the backup codes
533 *
534 * @since 1.7
535 *
536 * @return string
537 */
538 public static function get_generate_codes_link() {
539 $nonce = self::json_nonce();
540
541 $label = __( 'Backup 2FA methods:', 'wp-2fa' );
542
543 return $label . '</th><td><a href="#" class="button button-primary remove-2fa" data-trigger-generate-backup-codes data-nonce="' . esc_attr( $nonce ) . '" onclick="MicroModal.show( \'configure-2fa-backup-codes\' );">' . __( 'Generate list of backup codes', 'wp-2fa' ) . '</a>';
544 }
545
546 /**
547 * Shows the wrapper where backup code are generated and showed to the user
548 *
549 * @param boolean $backup_only - If we want to show backup window only - sets the class of the div to active.
550 *
551 * @since 1.7
552 *
553 * @return void
554 */
555 public static function generated_backup_codes( $backup_only = false ) {
556 $nonce = self::json_nonce();
557
558 $redirect = self::determine_redirect_url();
559
560 ?>
561 <div class="step-setting-wrapper align-center<?php echo ( $backup_only ) ? ' active' : ''; ?>" data-step-title="<?php esc_html_e( 'Your backup codes', 'wp-2fa' ); ?>">
562 <div class="mb-20">
563 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_generated', true ) ); ?>
564 </div>
565 <div class="backup-key-wrapper">
566 <textarea id="backup-codes-wrapper" readonly rows="4" cols="50" class="app-key"></textarea>
567 </div>
568 <div class="wp2fa-setup-actions">
569 <?php if ( is_ssl() ) { ?>
570 <button class="button button-primary wp-2fa-button-primary" type="submit" value="<?php esc_attr_e( 'Download', 'wp-2fa' ); ?>" data-trigger-backup-code-copy>
571 <?php esc_html_e( 'Copy', 'wp-2fa' ); ?>
572 </button>
573 <?php } else { ?>
574 <button class="button button-primary wp-2fa-button-primary" type="submit" value="<?php esc_attr_e( 'Download', 'wp-2fa' ); ?>" data-trigger-backup-code-download data-user="<?php echo esc_attr( self::get_user()->get_2fa_wp_user()->display_name ); ?>" data-website-url="<?php echo esc_attr( get_home_url() ); ?>">
575 <?php esc_html_e( 'Download', 'wp-2fa' ); ?>
576 </button>
577 <?php } ?>
578 <button class="button button-primary wp-2fa-button-primary" type="submit" value="<?php esc_attr_e( 'Print', 'wp-2fa' ); ?>" data-trigger-print data-nonce="<?php echo esc_attr( $nonce ); ?>" data-user-id="<?php echo esc_attr( self::get_user()->get_2fa_wp_user()->display_name ); ?>" data-website-url="<?php echo esc_attr( get_home_url() ); ?>">
579 <?php esc_html_e( 'Print', 'wp-2fa' ); ?>
580 </button>
581
582 <button class="button button-primary wp-2fa-button-primary" type="submit" value="<?php esc_attr_e( 'Send me the codes via email', 'wp-2fa' ); ?>" data-trigger-backup-code-email data-nonce="<?php echo esc_attr( wp_create_nonce( 'wp-2fa-send-backup-codes-email-nonce' ) ); ?>" data-user-id="<?php echo esc_attr( self::get_user()->get_2fa_wp_user()->ID ); ?>" data-website-url="<?php echo esc_attr( get_home_url() ); ?>">
583 <?php esc_html_e( 'Send me the codes via email', 'wp-2fa' ); ?>
584 </button>
585 <?php
586 if ( ! empty( $redirect ) ) {
587 ?>
588 <a href="<?php echo esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary wp-2fa-button-secondary close-first-time-wizard">
589 <?php esc_html_e( 'I\'m ready, close the wizard', 'wp-2fa' ); ?>
590 </a>
591 <?php
592 } else {
593 ?>
594 <button class="button button-secondary wp-2fa-button-secondary wp-2fa-button-secondary" type="submit" data-close-2fa-modal-and-refresh>
595 <?php esc_html_e( 'I\'m ready, close the wizard', 'wp-2fa' ); ?>
596 </button>
597 <?php } ?>
598 </div>
599 </div>
600 <?php
601 }
602
603 /**
604 * Final step for congratulating the user
605 *
606 * @since 1.7
607 *
608 * @param boolean $setup_wizard - Is that a call from setup wizard or not.
609 *
610 * @return void
611 */
612 public static function congratulations_step( $setup_wizard = false ) {
613
614 if ( $setup_wizard ) {
615 self::congratulations_step_plugin_wizard();
616 return;
617 }
618 ?>
619
620 <div class="step-setting-wrapper active">
621 <div class="mb-20">
622 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'no_further_action', true ) ); ?>
623 </div>
624 <div class="wp2fa-setup-actions">
625 <button class="modal__btn wp-2fa-button-secondary button" data-close-2fa-modal aria-label="Close this dialog window"><?php esc_html_e( 'Close wizard', 'wp-2fa' ); ?></button>
626 </div>
627 </div>
628 <?php
629 }
630
631 /**
632 * Final step for congratulating the user
633 *
634 * @since 1.7
635 *
636 * @return void
637 */
638 public static function congratulations_step_plugin_wizard() {
639 $redirect = ( '' !== self::determine_redirect_url() ) ? self::determine_redirect_url() : get_edit_profile_url( self::get_user()->get_2fa_wp_user()->ID );
640 $slide_title = ( User_Helper::is_excluded( self::get_user()->get_2fa_wp_user()->ID ) ) ? esc_html__( 'Congratulations.', 'wp-2fa' ) : esc_html__( 'Congratulations, you\'re almost there...', 'wp-2fa' );
641 ?>
642 <h3><?php echo \esc_html( $slide_title ); ?></h3>
643 <p><?php esc_html_e( 'Great job, the plugin and 2FA policies are now configured. You can always change the plugin settings and 2FA policies at a later stage from the WP 2FA entry in the WordPress menu.', 'wp-2fa' ); ?></p>
644
645 <?php
646 if ( User_Helper::is_excluded( self::get_user()->get_2fa_wp_user()->ID ) ) {
647 ?>
648 <div class="wp2fa-setup-actions">
649 <a href="<?php echo esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary close-first-time-wizard">
650 <?php esc_html_e( 'Close wizard', 'wp-2fa' ); ?>
651 </a>
652 </div>
653 <?php
654 } else {
655 ?>
656 <p><?php esc_html_e( 'Now you need to configure 2FA for your own user account. You can do this now (recommended) or later.', 'wp-2fa' ); ?></p>
657 <div class="wp2fa-setup-actions">
658 <a href="<?php echo esc_url( Settings::get_setup_page_link() ); ?>" class="button button-primary wp-2fa-button-secondary">
659 <?php esc_html_e( 'Configure 2FA now', 'wp-2fa' ); ?>
660 </a>
661 <a href="<?php echo esc_url( Settings::get_settings_page_link() ); ?>" class="button button-secondary wp-2fa-button-secondary close-first-time-wizard">
662 <?php esc_html_e( 'Close wizard & configure 2FA later', 'wp-2fa' ); ?>
663 </a>
664 </div>
665 <?php } ?>
666 <?php
667 }
668
669 /**
670 * Shows the methods in the modal wizard, so the user can choose from the available ones
671 *
672 * @return void
673 */
674 public static function show_modal_methods() {
675 if ( self::is_totp_enabled() ) {
676 ?>
677 <div class="wizard-step" id="2fa-wizard-totp">
678 <fieldset>
679 <?php self::totp_configure(); ?>
680 </fieldset>
681 </div>
682 <?php
683 }
684 if ( self::is_mail_enabled() ) {
685 ?>
686 <div class="wizard-step" id="2fa-wizard-email">
687 <fieldset>
688 <?php self::email_configure(); ?>
689 </fieldset>
690 </div>
691 <?php
692 }
693
694 /**
695 * Add an option for external providers to add their own modal methods options.
696 *
697 * @since 2.0.0
698 */
699 do_action( WP_2FA_PREFIX . 'modal_methods' );
700 }
701
702 /**
703 * Gets the current user
704 *
705 * @since 1.7
706 *
707 * @return \WP2FA\Admin\User
708 */
709 public static function get_user() {
710 if ( null === self::$user ) {
711 self::$user = User::get_instance();
712 }
713
714 return self::$user;
715 }
716
717 /**
718 * Choosing backup method step
719 * When there are more than one backup method - give the user ability to choose one
720 *
721 * @return void
722 *
723 * @since 2.0.0
724 */
725 public static function choose_backup_method() {
726 $redirect = self::determine_redirect_url();
727 ?>
728 <div class="wizard-step" id="2fa-wizard-backup-methods">
729 <div class="option-pill mb-20">
730 <?php echo wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_intro_multi', true ) ); ?>
731 </div>
732 <div class="radio-cells">
733 <?php
734 $backup_methods = Settings::get_backup_methods();
735
736 $i = 0;
737 foreach ( $backup_methods as $method_name => $method ) {
738 $checked = '';
739 if ( ! $i ) {
740 $checked = ' checked="checked"';
741 }
742 $i = 1;
743 ?>
744 <div class="option-pill"><label for="<?php echo \esc_attr( $method_name ); ?>"><input name="backup_method_select" data-step="<?php echo \esc_attr( $method['wizard-step'] ); ?>" type="radio" id="<?php echo \esc_attr( $method_name ); ?>" <?php echo $checked; ?>><?php echo $method['button_name']; // phpcs:ignore ?></label><br /></div>
745 <?php
746 }
747 ?>
748 </div>
749 <div class="wp2fa-setup-actions">
750 <a id="select-backup-method" href="<?php echo esc_url( Settings::get_setup_page_link() ); ?>" class="button button-primary wp-2fa-button-primary">
751 <?php esc_html_e( 'Configure backup 2FA method', 'wp-2fa' ); ?>
752 </a>
753 <a href="<?php echo esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary close-first-time-wizard" <?php echo ( ( '' === trim( $redirect ) ) ? 'data-close-it=""' : '' ); ?> >
754 <?php esc_html_e( 'Close wizard & configure 2FA later', 'wp-2fa' ); ?>
755 </a>
756 <script>
757 const closeButton = document.querySelector('[data-close-it]');
758
759 closeButton.addEventListener('click', (event) => {
760 event.preventDefault();
761 let url = new URL( location.href );
762 let params = new URLSearchParams( url.search );
763 params.delete('show');
764 location.replace( `${location.pathname}?${params}` );
765 });
766 </script>
767 </div>
768 </div>
769 <?php
770 }
771
772 /**
773 * Determines the redirect url for the user
774 *
775 * @return string
776 *
777 * @since 2.0.0
778 */
779 public static function determine_redirect_url(): string {
780 if ( null === self::$redirect_url ) {
781 $redirect_page = Settings::get_role_or_default_setting( 'redirect-user-custom-page-global', self::get_user()->get_2fa_wp_user() );
782 self::$redirect_url = ( '' !== trim( $redirect_page ) ) ? \trailingslashit( get_site_url() ) . $redirect_page : '';
783
784 if (
785 'yes' === Settings::get_role_or_default_setting( 'create-custom-user-page', self::get_user()->get_2fa_wp_user() ) ||
786 'yes' === Settings::get_role_or_default_setting( 'create-custom-user-page' ) ) {
787 if (
788 '' !== trim( Settings::get_role_or_default_setting( 'redirect-user-custom-page', self::get_user()->get_2fa_wp_user() ) ) ||
789 '' !== trim( Settings::get_role_or_default_setting( 'redirect-user-custom-page' ) ) ) {
790 if ( 'yes' === Settings::get_role_or_default_setting( 'create-custom-user-page', self::get_user()->get_2fa_wp_user() ) ) {
791 self::$redirect_url = trailingslashit( get_site_url() ) . Settings::get_role_or_default_setting( 'redirect-user-custom-page', self::get_user()->get_2fa_wp_user() );
792 } else {
793 self::$redirect_url = trailingslashit( get_site_url() ) . Settings::get_role_or_default_setting( 'redirect-user-custom-page' );
794 }
795 }
796 }
797 }
798
799 return self::$redirect_url;
800 }
801
802 /**
803 * Generates nonce for JSON calls
804 *
805 * @since 1.7
806 *
807 * @return string
808 */
809 protected static function json_nonce() {
810 if ( null === self::$json_nonce ) {
811 self::$json_nonce = wp_create_nonce( 'wp-2fa-backup-codes-generate-json-' . self::get_user()->get_2fa_wp_user()->ID );
812 }
813
814 return self::$json_nonce;
815 }
816
817 /**
818 * Returns the status of the totp method (enabled | disabled)
819 *
820 * @since 1.7
821 *
822 * @return boolean
823 */
824 private static function is_totp_enabled(): bool {
825 if ( null === self::$totp_enabled ) {
826 self::$totp_enabled = empty( Settings::get_role_or_default_setting( 'enable_totp', 'current' ) ) ? false : true;
827 }
828
829 return self::$totp_enabled;
830 }
831
832 /**
833 * Returns the status of the mail method (enabled | disabled)
834 *
835 * @since 1.7
836 *
837 * @return boolean
838 */
839 private static function is_mail_enabled(): bool {
840 if ( null === self::$email_enabled ) {
841 self::$email_enabled = empty( Settings::get_role_or_default_setting( 'enable_email', 'current' ) ) ? false : true;
842 }
843
844 return self::$email_enabled;
845 }
846
847 /**
848 * Retrieves the QR code
849 *
850 * @since 1.7
851 *
852 * @return string
853 */
854 private static function get_qr_code(): string {
855
856 // Setup site information, used when generating our QR code.
857 $site_name = site_url();
858 $site_name = trim( str_replace( array( 'http://', 'https://' ), '', $site_name ), '/' );
859 /**
860 * Changing the title of the login screen for the TOTP method.
861 *
862 * @param string $title - The default title.
863 * @param \WP_User $user - The WP user.
864 *
865 * @since 2.0.0
866 */
867 $totp_title = apply_filters(
868 WP_2FA_PREFIX . 'totp_title',
869 $site_name . ':' . self::get_user()->get_2fa_wp_user()->user_login,
870 self::get_user()->get_2fa_wp_user()
871 );
872
873 return Authentication::get_google_qr_code( $totp_title, self::get_user()->get_totp_key(), $site_name );
874 }
875 }
876