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