PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.8.0
WP 2FA – Two-factor authentication for WordPress v2.8.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 1 year ago class-grace-period-notifications.php 1 year ago class-passord-reset-2fa.php 1 year ago class-re-login-2fa.php 1 year ago class-wizard-steps.php 1 year ago index.php 1 year ago
class-wizard-steps.php
486 lines
1 <?php
2 /**
3 * Settings page render class.
4 *
5 * @package wp2fa
6 * @subpackage views
7 * @copyright 2024 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\WP_Helper;
17 use WP2FA\Admin\Helpers\User_Helper;
18 use WP2FA\Admin\Controllers\Settings;
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 * Holds the nonce for json calls
32 *
33 * @since 1.7
34 *
35 * @var string
36 */
37 private static $json_nonce = null;
38
39 /**
40 * Holds the url to which to redirect the user after the setup is finished
41 *
42 * @var string
43 *
44 * @since 2.0.0
45 */
46 private static $redirect_url = null;
47
48 /**
49 * Introduction step form
50 *
51 * @since 1.7
52 *
53 * @return void
54 */
55 public static function optional_user_welcome_step() {
56 ?>
57 <div class="wizard-step active">
58 <div class="mb-20">
59 <?php echo \wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'welcome', true ) ); ?>
60 </div>
61
62 <div class="wp2fa-setup-actions">
63 <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>
64 <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>
65 </div>
66 </div>
67 <?php
68 }
69
70 /**
71 * Introduction step form
72 *
73 * @since 1.7
74 *
75 * @return void
76 */
77 public static function introduction_step() {
78 ?>
79 <form method="post" class="wp2fa-setup-form">
80 <?php wp_nonce_field( 'wp2fa-step-addon' ); ?>
81 <div class="mb-20">
82 <?php echo \wp_kses_post( WP2FA::get_wp2fa_white_label_setting( '2fa_required_intro', true ) ); ?>
83 </div>
84
85 <div class="wp2fa-setup-actions">
86 <button class="button button-primary wp-2fa-button-primary"
87 type="submit"
88 name="save_step"
89 value="<?php \esc_attr_e( 'Next', 'wp-2fa' ); ?>">
90 <?php \esc_html_e( 'Next', 'wp-2fa' ); ?>
91 </button>
92 </div>
93 </form>
94 <?php
95 }
96
97 /**
98 * Welcome step of the wizard
99 *
100 * @since 1.7
101 *
102 * @param string $next_step - url of the next step.
103 *
104 * @return void
105 */
106 public static function welcome_step( $next_step ) {
107 $redirect = Settings::get_settings_page_link();
108
109 ?>
110 <h3><?php \esc_html_e( 'Let us help you get started', 'wp-2fa' ); ?></h3>
111 <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>
112
113 <div class="wp2fa-setup-actions">
114 <a class="button button-primary"
115 href="<?php echo \esc_url( $next_step ); ?>">
116 <?php \esc_html_e( 'Let’s get started!', 'wp-2fa' ); ?>
117 </a>
118 <a class="button button-secondary wp-2fa-button-secondary first-time-wizard"
119 href="<?php echo \esc_url( $redirect ); ?>">
120 <?php \esc_html_e( 'Skip Wizard - I know how to do this', 'wp-2fa' ); ?>
121 </a>
122 </div>
123 <?php
124 }
125
126 /**
127 * Configure backup codes step
128 *
129 * @since 1.7
130 *
131 * @return void
132 */
133 public static function backup_codes_configure() {
134
135 $user_type = User_Utils::determine_user_2fa_status( User_Helper::get_user_object() );
136
137 $redirect = self::determine_redirect_url();
138 ?>
139 <div class="step-setting-wrapper active">
140 <?php
141 if ( in_array( 'user_needs_to_setup_backup_codes', $user_type, true ) ) {
142 ?>
143 <div class="mb-20">
144 <?php echo \wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_intro', true ) ); ?>
145 </div>
146 <?php } else { ?>
147 <div class="mb-20">
148 <?php echo \wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_intro_continue', true ) ); ?>
149 </div>
150 <?php } ?>
151 <div class="wp2fa-setup-actions">
152 <?php if ( in_array( 'user_needs_to_setup_backup_codes', $user_type, true ) ) { ?>
153 <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 <?php echo WP_Helper::create_data_nonce( self::json_nonce() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
154 <?php \esc_html_e( 'Generate list of backup codes', 'wp-2fa' ); ?>
155 </button>
156 <?php
157 if ( ! empty( $redirect ) ) {
158 ?>
159 <a href="<?php echo \esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary wp-2fa-button-secondary close-first-time-wizard">
160 <?php \esc_html_e( 'I’ll generate them later', 'wp-2fa' ); ?>
161 </a>
162 <?php
163 } else {
164 ?>
165 <a href="#" class="button wp-2fa-button-secondary" data-close-2fa-modal value="<?php \esc_attr_e( 'I’ll generate them later', 'wp-2fa' ); ?>">
166 <?php \esc_html_e( 'I’ll generate them later', 'wp-2fa' ); ?>
167 </a>
168 <?php } ?>
169 <?php } else { ?>
170 <?php
171 if ( ! empty( $redirect ) ) {
172 ?>
173 <a href="<?php echo \esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary close-first-time-wizard">
174 <?php \esc_html_e( 'Close wizard', 'wp-2fa' ); ?>
175 </a>
176 <?php
177 } else {
178 ?>
179 <a href="#" class="button button-secondary wp-2fa-button-secondary" data-reload>
180 <?php \esc_html_e( 'Close wizard', 'wp-2fa' ); ?>
181 </a>
182 <?php } ?>
183 <?php } ?>
184 </div>
185 </div>
186 <?php
187 }
188
189 /**
190 * Generate backup codes step
191 *
192 * @since 1.7
193 *
194 * @return void
195 */
196 public static function generate_backup_codes() {
197 ?>
198 <div class="step-setting-wrapper active" data-step-title="<?php \esc_html_e( 'Generate codes', 'wp-2fa' ); ?>">
199 <div class="mb-20">
200 <?php echo \wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_generate_intro', true ) ); ?>
201 </div>
202 <div class="wp2fa-setup-actions">
203 <button class="button button-primary" name="next_step_setting" value="<?php \esc_attr_e( 'Generate backup codes', 'wp-2fa' ); ?>" data-trigger-generate-backup-codes <?php echo WP_Helper::create_data_nonce( self::json_nonce() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
204 <?php \esc_html_e( 'Generate list of backup codes', 'wp-2fa' ); ?>
205 </button>
206 <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="">
207 <?php \esc_html_e( 'I’ll generate them later', 'wp-2fa' ); ?>
208 </a>
209 </div>
210 </div>
211
212 <?php
213 }
214
215 /**
216 * Creates link for generating the backup codes
217 *
218 * @since 1.7
219 *
220 * @return string
221 */
222 public static function get_generate_codes_label() {
223 $label = __( 'Backup 2FA methods:', 'wp-2fa' );
224
225 return $label . '</th><td>';
226 }
227
228 /**
229 * Creates backup codes URL link
230 *
231 * @return string
232 *
233 * @since 2.6.0
234 */
235 public static function get_backup_codes_link(): string {
236 return '<a href="#" class="button button-primary remove-2fa" data-trigger-generate-backup-codes ' . WP_Helper::create_data_nonce( self::json_nonce() ) . ' onclick="MicroModal.show( \'configure-2fa-backup-codes\' );">' . __( 'Generate list of backup codes', 'wp-2fa' ) . '</a>';
237 }
238
239 /**
240 * Shows the wrapper where backup code are generated and showed to the user
241 *
242 * @param boolean $backup_only - If we want to show backup window only - sets the class of the div to active.
243 *
244 * @since 1.7
245 *
246 * @return void
247 */
248 public static function generated_backup_codes( $backup_only = false ) {
249
250 $redirect = self::determine_redirect_url();
251
252 ?>
253 <div class="step-setting-wrapper align-center<?php echo ( $backup_only ) ? ' active' : ''; ?>" data-step-title="<?php \esc_html_e( 'Your backup codes', 'wp-2fa' ); ?>">
254 <div class="mb-20">
255 <?php echo \wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_generated', true ) ); ?>
256 </div>
257 <div class="backup-key-wrapper">
258 <textarea id="backup-codes-wrapper" readonly rows="4" cols="50" class="app-key"></textarea>
259 </div>
260 <div class="wp2fa-setup-actions">
261 <?php if ( is_ssl() ) { ?>
262 <button class="button button-primary wp-2fa-button-primary" type="submit" value="<?php \esc_attr_e( 'Download', 'wp-2fa' ); ?>" data-trigger-backup-code-copy>
263 <?php \esc_html_e( 'Copy', 'wp-2fa' ); ?>
264 </button>
265 <?php } else { ?>
266 <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() ); ?>">
267 <?php \esc_html_e( 'Download', 'wp-2fa' ); ?>
268 </button>
269 <?php } ?>
270 <button class="button button-primary wp-2fa-button-primary" type="submit" value="<?php \esc_attr_e( 'Print', 'wp-2fa' ); ?>" data-trigger-print <?php echo WP_Helper::create_data_nonce( self::json_nonce() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> data-user-id="<?php echo \esc_attr( User_Helper::get_user_object()->display_name ); ?>" data-website-url="<?php echo \esc_attr( get_home_url() ); ?>">
271 <?php \esc_html_e( 'Print', 'wp-2fa' ); ?>
272 </button>
273
274 <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 <?php echo WP_Helper::create_data_nonce( 'wp-2fa-send-backup-codes-email-nonce' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> data-user-id="<?php echo \esc_attr( User_Helper::get_user_object()->ID ); ?>" data-website-url="<?php echo \esc_attr( get_home_url() ); ?>">
275 <?php \esc_html_e( 'Send me the codes via email', 'wp-2fa' ); ?>
276 </button>
277 <?php
278 if ( ! empty( $redirect ) ) {
279 ?>
280 <a href="<?php echo \esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary wp-2fa-button-secondary close-first-time-wizard">
281 <?php \esc_html_e( 'I\'m ready, close the wizard', 'wp-2fa' ); ?>
282 </a>
283 <?php
284 } else {
285 ?>
286 <button class="button button-secondary wp-2fa-button-secondary wp-2fa-button-secondary" type="submit" data-close-2fa-modal-and-refresh>
287 <?php \esc_html_e( 'I\'m ready, close the wizard', 'wp-2fa' ); ?>
288 </button>
289 <?php } ?>
290 </div>
291 </div>
292 <?php
293 }
294
295 /**
296 * Final step for congratulating the user
297 *
298 * @since 1.7
299 *
300 * @param boolean $setup_wizard - Is that a call from setup wizard or not.
301 *
302 * @return void
303 */
304 public static function congratulations_step( $setup_wizard = false ) {
305
306 if ( $setup_wizard ) {
307 self::congratulations_step_plugin_wizard();
308 return;
309 }
310
311 $redirect = ( '' !== self::determine_redirect_url() ) ? self::determine_redirect_url() : '';
312 ?>
313
314 <div class="step-setting-wrapper active">
315 <div class="mb-20">
316 <?php echo \wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'no_further_action', true ) ); ?>
317 </div>
318 <div class="wp2fa-setup-actions">
319 <?php if ( '' !== trim( $redirect ) ) { ?>
320 <a href="<?php echo \esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary close-first-time-wizard">
321 <?php \esc_html_e( 'Close wizard', 'wp-2fa' ); ?>
322 </a>
323 <?php } else { ?>
324 <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>
325 <?php } ?>
326 </div>
327 </div>
328 <?php
329 }
330
331 /**
332 * Final step for congratulating the user
333 *
334 * @since 1.7
335 *
336 * @return void
337 */
338 public static function congratulations_step_plugin_wizard() {
339 $redirect = ( '' !== self::determine_redirect_url() ) ? self::determine_redirect_url() : get_edit_profile_url( User_Helper::get_user_object()->ID );
340 $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' );
341 ?>
342 <h3><?php echo \esc_html( $slide_title ); ?></h3>
343 <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>
344
345 <?php
346 if ( User_Helper::is_excluded( User_Helper::get_user_object()->ID ) ) {
347 ?>
348 <div class="wp2fa-setup-actions">
349 <a href="<?php echo \esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary close-first-time-wizard">
350 <?php \esc_html_e( 'Close wizard', 'wp-2fa' ); ?>
351 </a>
352 </div>
353 <?php
354 } else {
355 ?>
356 <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>
357 <div class="wp2fa-setup-actions">
358 <a href="<?php echo \esc_url( Settings::get_setup_page_link() ); ?>" class="button button-primary wp-2fa-button-secondary">
359 <?php \esc_html_e( 'Configure 2FA now', 'wp-2fa' ); ?>
360 </a>
361 <a href="<?php echo \esc_url( Settings::get_settings_page_link() ); ?>" class="button button-secondary wp-2fa-button-secondary close-first-time-wizard">
362 <?php \esc_html_e( 'Close wizard & configure 2FA later', 'wp-2fa' ); ?>
363 </a>
364 </div>
365 <?php } ?>
366 <?php
367 }
368
369 /**
370 * Shows the methods in the modal wizard, so the user can choose from the available ones
371 *
372 * @return void
373 */
374 public static function show_modal_methods() {
375 /**
376 * Add an option for external providers to add their own modal methods options.
377 *
378 * @since 2.0.0
379 */
380 \do_action( WP_2FA_PREFIX . 'modal_methods' );
381 }
382
383 /**
384 * Choosing backup method step
385 * When there are more than one backup method - give the user ability to choose one
386 *
387 * @return void
388 *
389 * @since 2.0.0
390 */
391 public static function choose_backup_method() {
392 $redirect = self::determine_redirect_url();
393 ?>
394 <div class="wizard-step" id="2fa-wizard-backup-methods">
395 <div class="option-pill mb-20">
396 <?php echo \wp_kses_post( WP2FA::get_wp2fa_white_label_setting( 'backup_codes_intro_multi', true ) ); ?>
397 </div>
398 <div class="radio-cells">
399 <?php
400 $backup_methods = Settings::get_backup_methods();
401
402 $i = 0;
403 foreach ( $backup_methods as $method_name => $method ) {
404 $checked = '';
405 if ( ! $i ) {
406 $checked = ' checked="checked"';
407 }
408 $i = 1;
409 ?>
410 <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>
411 <?php
412 }
413 ?>
414 </div>
415 <div class="wp2fa-setup-actions">
416 <a id="select-backup-method" href="<?php echo \esc_url( Settings::get_setup_page_link() ); ?>" class="button button-primary wp-2fa-button-primary">
417 <?php \esc_html_e( 'Configure backup 2FA method', 'wp-2fa' ); ?>
418 </a>
419 <a href="<?php echo \esc_url( $redirect ); ?>" class="button button-secondary wp-2fa-button-secondary close-first-time-wizard" <?php echo ( ( '' === trim( (string) $redirect ) ) ? 'data-close-it=""' : '' ); ?> >
420 <?php \esc_html_e( 'Close wizard & configure 2FA later', 'wp-2fa' ); ?>
421 </a>
422 <script>
423 const closeButton = document.querySelector('[data-close-it]');
424
425 if (closeButton) {
426 closeButton.addEventListener('click', (event) => {
427 event.preventDefault();
428 let url = new URL( location.href );
429 let params = new URLSearchParams( url.search );
430 params.delete('show');
431 location.replace( `${location.pathname}?${params}` );
432 });
433 }
434 </script>
435 </div>
436 </div>
437 <?php
438 }
439
440 /**
441 * Determines the redirect url for the user
442 *
443 * @return string
444 *
445 * @since 2.0.0
446 */
447 public static function determine_redirect_url(): string {
448 if ( null === self::$redirect_url ) {
449 $redirect_page = Settings::get_role_or_default_setting( 'redirect-user-custom-page-global', User_Helper::get_user_object() );
450 self::$redirect_url = ( '' !== trim( (string) $redirect_page ) ) ? \trailingslashit( get_site_url() ) . $redirect_page : '';
451
452 if (
453 'yes' === Settings::get_role_or_default_setting( 'create-custom-user-page', User_Helper::get_user_object() ) ||
454 'yes' === Settings::get_role_or_default_setting( 'create-custom-user-page' ) ) {
455 if (
456 '' !== trim( (string) Settings::get_role_or_default_setting( 'redirect-user-custom-page', User_Helper::get_user_object() ) ) ||
457 '' !== trim( (string) Settings::get_role_or_default_setting( 'redirect-user-custom-page' ) ) ) {
458 if ( 'yes' === Settings::get_role_or_default_setting( 'create-custom-user-page', User_Helper::get_user_object() ) ) {
459 self::$redirect_url = trailingslashit( get_site_url() ) . Settings::get_role_or_default_setting( 'redirect-user-custom-page', User_Helper::get_user_object() );
460 } else {
461 self::$redirect_url = trailingslashit( get_site_url() ) . Settings::get_role_or_default_setting( 'redirect-user-custom-page' );
462 }
463 }
464 }
465 }
466
467 return self::$redirect_url;
468 }
469
470 /**
471 * Generates nonce for JSON calls
472 *
473 * @since 1.7
474 *
475 * @return string
476 */
477 protected static function json_nonce() {
478 if ( null === self::$json_nonce ) {
479 self::$json_nonce = 'wp-2fa-backup-codes-generate-json-' . User_Helper::get_user_object()->ID;
480 }
481
482 return self::$json_nonce;
483 }
484 }
485 }
486