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