PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 1.4.1
WP 2FA – Two-factor authentication for WordPress v1.4.1
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 / UserProfile.php
wp-2fa / includes / classes / Admin Last commit date
SettingsPage.php 5 years ago SetupWizard.php 5 years ago UserNotices.php 5 years ago UserProfile.php 5 years ago UserRegistered.php 5 years ago
UserProfile.php
1038 lines
1 <?php // phpcs:ignore
2
3 namespace WP2FA\Admin;
4
5 use \WP2FA\Authenticator\Authentication as Authentication;
6 use \WP2FA\WP2FA as WP2FA;
7 use \WP2FA\Core as Core;
8 use \WP2FA\Authenticator\BackupCodes as BackupCodes;
9
10 /**
11 * UserProfile - Class for handling user things such as profile settings and admin list views.
12 */
13 class UserProfile {
14
15 const NOTICES_META_KEY = 'wp_2fa_totp_notices';
16
17 /**
18 * Classs constructor
19 */
20 public function __construct() {
21 }
22
23 /**
24 * Add our buttons to the user profile editing screen.
25 *
26 * @param object $user User data.
27 */
28 public function user_2fa_options( $user ) {
29
30 if ( isset( $_GET['user_id'] ) ) {
31 $user_id = (int) $_GET['user_id'];
32 $user = get_user_by( 'id', $user_id );
33 } else {
34 $user = wp_get_current_user();
35 }
36
37 // Get current user, we going to need this regardless.
38 $current_user = wp_get_current_user();
39
40 // Bail if we still dont have an object.
41 if ( ! is_a( $user, '\WP_User' ) || ! is_a( $current_user, '\WP_User' ) ) {
42 return;
43 }
44
45 $roles = (array) $user->roles;
46
47 // Grab grace period UNIX time.
48 $grace_period_expired = get_user_meta( $user->ID, 'wp_2fa_user_grace_period_expired', true );
49 // Grab current time, we going to compare these later.
50 $time_now = time();
51 $is_user_excluded = WP2FA::is_user_excluded( $user->ID );
52
53 // First lets see if the user already has a token.
54 $enabled_methods = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
55
56 if ( ! $grace_period_expired && $current_user->ID === $user->ID && ! $is_user_excluded && ! empty( $roles ) ) {
57
58 // These are the buttons we show if a user has no enabled methods.
59 if ( ! empty( $enabled_methods && $user->ID === $current_user->ID ) ) {
60 // Create wizard link based on which 2fa methods are allowed by admin.
61 if ( ! empty( WP2FA::get_wp2fa_setting( 'enable_totp' ) ) && ! empty( WP2FA::get_wp2fa_setting( 'enable_email' ) ) ) {
62 if ( WP2FA::is_this_multisite() ) {
63 $button_link = admin_url( 'index.php?page=wp-2fa-setup&current-step=user_choose_2fa_method&wizard_type=user_2fa_config' );
64 } else {
65 $button_link = admin_url( 'options-general.php?page=wp-2fa-setup&current-step=user_choose_2fa_method&wizard_type=user_2fa_config' );
66 }
67
68 } else {
69 if ( WP2FA::is_this_multisite() ) {
70 $button_link = admin_url( 'index.php?page=wp-2fa-setup&current-step=reconfigure_method&wizard_type=user_reconfigure_config' );
71 } else {
72 $button_link = admin_url( 'options-general.php?page=wp-2fa-setup&current-step=reconfigure_method&wizard_type=user_reconfigure_config' );
73 }
74 }
75 // Create remove 2fa link.
76 $url = add_query_arg(
77 array(
78 'action' => 'remove_user_2fa',
79 'user_id' => $user->ID,
80 'wp_2fa_nonce' => wp_create_nonce( 'wp-2fa-remove-user-2fa-nonce' ),
81 ),
82 admin_url( 'user-edit.php' )
83 );
84 if ( WP2FA::is_this_multisite() ) {
85 $backup_codes_link = admin_url( 'index.php?page=wp-2fa-setup&current-step=backup_codes&wizard_type=backup_codes_config' );
86 } else {
87 $backup_codes_link = admin_url( 'options-general.php?page=wp-2fa-setup&current-step=backup_codes&wizard_type=backup_codes_config' );
88 }
89 ?>
90 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
91 <p class="description"><?php esc_html_e( 'Add two-factor authentication to strengthen the security of your WordPress user account.', 'wp-2fa' ); ?></p>
92 <table class="form-table" role="presentation">
93 <tbody>
94 <tr>
95 <th><label><?php esc_html_e( '2-Factor authentication', 'wp-2fa' ); ?></label></th>
96 <td>
97
98 <a href="<?php echo esc_url( $button_link ); ?>" class="button button-primary"><?php esc_html_e( 'Change 2FA Settings', 'wp-2fa' ); ?></a> <?php if ( empty( WP2FA::get_wp2fa_setting( 'hide_remove_button' ) ) ) : ?><a href="#" class="button button-primary remove-2fa" onclick="MicroModal.show('confirm-remove-2fa');"><?php esc_html_e( 'Remove 2FA', 'wp-2fa' ); ?></a><?php endif; ?>
99
100 <br />
101 <br />
102
103 <a href="<?php echo esc_url( $backup_codes_link ); ?>" class="button button-primary"><?php esc_html_e( 'Generate backup codes', 'wp-2fa' ); ?></a>
104 <?php
105 $codes_remaining = BackupCodes::codes_remaining_for_user( $user );
106 if ( $codes_remaining > 0 ) {
107 ?>
108 <span class="description mt-5px"><?php echo esc_attr( (int) $codes_remaining ); ?> <?php esc_html_e( 'unused backup codes remaining.', 'wp-2fa' ); ?></span>
109 <?php
110 } elseif ( 0 === $codes_remaining ) {
111 ?>
112 <a class="learn_more_link" href="https://www.wpwhitesecurity.com/2fa-backup-codes/?utm_source=plugin&utm_medium=referral&utm_campaign=wp2fa&utm_content=settings+pages" target="_blank"><?php esc_html_e( 'Learn more.', 'wp-2fa' ); ?></a>
113 <?php
114 }
115 ?>
116 </td>
117 </tr>
118 </tbody>
119 </table>
120 <div class="wp2fa-modal micromodal-slide" id="confirm-remove-2fa" aria-hidden="true">
121 <div class="modal__overlay" tabindex="-1" data-micromodal-close>
122 <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
123 <header class="modal__header">
124 <h4 class="modal__title" id="modal-1-title">
125 <?php esc_html_e( 'Remove 2FA?', 'wp-2fa' ); ?>
126 </h4>
127 <button class="modal__close" aria-label="Close modal" data-micromodal-close></button>
128 </header>
129 <main class="modal__content" id="modal-1-content">
130 <p>
131 <?php esc_html_e( 'Are you sure you want to remove two-factor authentication and lower the security of your user account?', 'wp-2fa' ); ?>
132 </p>
133 </main>
134 <footer class="modal__footer">
135 <a href="<?php echo esc_url( $url ); ?>" class="modal__btn modal__btn-primary"><?php esc_html_e( 'Yes', 'wp-2fa' ); ?></a>
136 <button class="modal__btn" data-micromodal-close aria-label="Close this dialog window"><?php esc_html_e( 'No', 'wp-2fa' ); ?></button>
137 </footer>
138 </div>
139 </div>
140 </div>
141
142 <?php
143 } else {
144
145 if ( WP2FA::is_this_multisite() ) {
146 $first_time_setup_link = admin_url( 'index.php?page=wp-2fa-setup&current-step=choose_2fa_method&first_time_setup=true' );
147 } else {
148 $first_time_setup_link = admin_url( 'options-general.php?page=wp-2fa-setup&current-step=choose_2fa_method&first_time_setup=true' );
149 }
150 ?>
151 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
152 <p class="description"><?php esc_html_e( 'Add two-factor authentication to strengthen the security of your WordPress user account.', 'wp-2fa' ); ?></p>
153 <table class="form-table" role="presentation">
154 <tbody>
155 <tr>
156 <th><label><?php esc_html_e( '2-Factor authentication', 'wp-2fa' ); ?></label></th>
157 <td>
158 <a href="<?php echo esc_url( $first_time_setup_link ); ?>" class="button button-primary"><?php esc_html_e( 'Configure Two-factor authentication (2FA)', 'wp-2fa' ); ?></a>
159 </td>
160 </tr>
161 </tbody>
162 </table>
163 <?php
164 }
165 } elseif ( $is_user_excluded ) {
166 ?>
167 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
168 <p class="description"><?php esc_html_e( 'Add two-factor authentication to strengthen the security of your WordPress user account.', 'wp-2fa' ); ?></p>
169 <p class="description"><?php esc_html_e( 'Your user / role is not permitted to configure 2FA. Contact your administrator for more information.', 'wp-2fa' ); ?></p>
170 <?php
171 } elseif ( $grace_period_expired && current_user_can( 'manage_options' ) ) {
172 ?>
173 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
174 <table class="form-table" role="presentation">
175 <tbody>
176 <tr>
177 <th><label><?php esc_html_e( '2-Factor authentication', 'wp-2fa' ); ?></label></th>
178 <td>
179 <?php
180 $url = add_query_arg(
181 array(
182 'action' => 'unlock_account',
183 'user_id' => $user->ID,
184 'wp_2fa_nonce' => wp_create_nonce( 'wp-2fa-unlock-account-nonce' ),
185 ),
186 admin_url( 'user-edit.php' )
187 );
188
189 if ( $grace_period_expired ) {
190 ?>
191 <a href="<?php echo esc_url( $url ); ?>" class="button button-primary"><?php esc_html_e( 'Unlock user and reset the grace period', 'wp-2fa' ); ?></a>
192 <?php
193 }
194 ?>
195 </td>
196 </tr>
197 </tbody>
198 </table>
199 <?php
200 } elseif ( ! $grace_period_expired && current_user_can( 'manage_options' ) && ! empty( $enabled_methods ) ) {
201 ?>
202 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
203 <p class="description"><?php esc_html_e( 'By resetting this user\'s 2FA configuration you disable the currently configured 2FA so the user can log back in using a usemame and a password only. *the user if enforced to setup 2FA the user will get a prompt upon logging in, from where 2FA can be configured. The user has to configure 2FA within the configured grace period.', 'wp-2fa' ); ?></p>
204 <table class="form-table" role="presentation">
205 <tbody>
206 <tr>
207 <th><label><?php esc_html_e( '2-Factor authentication', 'wp-2fa' ); ?></label></th>
208 <td>
209 <?php
210 // Create remove 2fa link.
211 $url = add_query_arg(
212 array(
213 'action' => 'remove_user_2fa',
214 'user_id' => $user->ID,
215 'wp_2fa_nonce' => wp_create_nonce( 'wp-2fa-remove-user-2fa-nonce' ),
216 'admin_reset' => 'yes',
217 ),
218 admin_url( 'user-edit.php' )
219 );
220 ?>
221 <a href="<?php echo esc_url( $url ); ?>" class="button button-primary"><?php esc_html_e( 'Reset 2FA configuration', 'wp-2fa' ); ?></a>
222 </td>
223 </tr>
224 </tbody>
225 </table>
226 <?php
227 } elseif ( empty( $roles ) ) {
228 echo $this->inline_2fa_profile_form();
229 }
230
231 }
232
233 /**
234 * Produces the 2FA configuration form for network users, or any user with no roles.
235 */
236 public function inline_2fa_profile_form( $is_shortcode = '', $show_preamble = 'true' ) {
237 if ( isset( $_GET['user_id'] ) ) {
238 $user_id = (int) $_GET['user_id'];
239 $user = get_user_by( 'id', $user_id );
240 } else {
241 $user = wp_get_current_user();
242 }
243
244 // Get current user, we going to need this regardless.
245 $current_user = wp_get_current_user();
246
247 // Bail if we still dont have an object.
248 if ( ! is_a( $user, '\WP_User' ) || ! is_a( $current_user, '\WP_User' ) ) {
249 return;
250 }
251
252 // Grab grace period UNIX time.
253 $grace_period_expired = get_user_meta( $user->ID, 'wp_2fa_grace_period_expiry', true );
254
255 // Grab current time, we going to compare these later.
256 $time_now = time();
257 $is_user_excluded = WP2FA::is_user_excluded( $user->ID );
258
259 // First lets see if the user already has a token.
260 $enabled_methods = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
261
262 if ( ! $is_user_excluded ) {
263
264 // Check if current user viewing the profile is the owner of the profile.
265 if ( isset( $_GET['user_id'] ) ) {
266 $user_id = (int) $_GET['user_id'];
267 $user = get_user_by( 'id', $user_id );
268 $curent_user = wp_get_current_user();
269 if ( $curent_user->ID !== $user->ID ) {
270 return;
271 }
272 }
273
274 // Show this to user who has enabled methods
275 if ( ! empty( $enabled_methods ) && $user->ID === $current_user->ID ) {
276 ?>
277 <?php if ( ! isset( $is_shortcode ) && ! $is_shortcode === 'output_shortcode' ) : ?>
278 <h2>
279 <?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?>
280 </h2>
281 <?php endif; ?>
282 <?php if ( 'true' === $show_preamble ) { ?>
283 <p class="description">
284 <?php esc_html_e( 'Add two-factor authentication to strengthen the security of your WordPress user account.', 'wp-2fa' ); ?>
285 </p>
286 <?php } ?>
287 <table class="form-table" role="presentation">
288 <tbody>
289 <tr>
290 <th>
291 <label>
292 <?php esc_html_e( '2-Factor authentication', 'wp-2fa' ); ?>
293 </label>
294 </th>
295 <td>
296 <a href="#" class="button button-primary remove-2fa" onclick="MicroModal.show('configure-2fa',{
297 onShow: modal => jQuery( '.wizard-step:first-of-type' ).addClass( 'active' ),
298 onClose: modal => jQuery( '.wizard-step.active' ).removeClass( 'active' ),
299 });"><?php esc_html_e( 'Change 2FA Settings', 'wp-2fa' ); ?></a>
300
301 <?php if ( empty( WP2FA::get_wp2fa_setting( 'hide_remove_button' ) ) ) : ?>
302 <a href="#" class="button button-primary remove-2fa" onclick="MicroModal.show('confirm-remove-2fa');"><?php esc_html_e( 'Remove 2FA', 'wp-2fa' ); ?></a>
303 <?php endif; ?>
304
305 <a href="#" class="button button-primary remove-2fa" onclick="MicroModal.show('configure-2fa-backup-codes',{
306 onShow: modal => jQuery( '.wizard-step:first-of-type' ).addClass( 'active' ),
307 onClose: modal => jQuery( '.wizard-step.active' ).removeClass( 'active' ),
308 });"><?php esc_html_e( 'Generate Backup Codes', 'wp-2fa' ); ?></a>
309
310 <?php
311 $codes_remaining = BackupCodes::codes_remaining_for_user( $user );
312 if ( $codes_remaining > 0 ) {
313 ?>
314 <span class="description mt-5px"><?php echo esc_attr( (int) $codes_remaining ); ?> <?php esc_html_e( 'unused backup codes remaining.', 'wp-2fa' ); ?></span>
315 <?php
316 } elseif ( 0 === $codes_remaining ) {
317 ?>
318 <a class="learn_more_link" href="https://www.wpwhitesecurity.com/2fa-backup-codes/?utm_source=plugin&utm_medium=referral&utm_campaign=wp2fa&utm_content=settings+pages" target="_blank"><?php esc_html_e( 'Learn more.', 'wp-2fa' ); ?></a>
319 <?php
320 }
321 ?>
322 <div>
323 <div class="wp2fa-modal micromodal-slide" id="confirm-remove-2fa" aria-hidden="true">
324 <div class="modal__overlay" tabindex="-1" data-micromodal-close>
325 <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
326 <header class="modal__header">
327 <button class="modal__close" aria-label="Close modal" data-micromodal-close></button>
328 </header>
329 <main class="modal__content" id="modal-1-content">
330 <div>
331 <h4>
332 <?php esc_html_e( 'Remove 2FA?', 'wp-2fa' ); ?>
333 </h4>
334 <p>
335 <?php esc_html_e( 'Are you sure you want to remove two-factor authentication and lower the security of your user account?', 'wp-2fa' ); ?>
336 </p>
337 </div>
338 </main>
339 <footer class="modal__footer">
340 <a href="#" class="modal__btn modal__btn-primary button" data-trigger-remove-2fa data-user-id="<?php echo esc_attr( $user->ID ); ?>" data-nonce="<?php echo wp_create_nonce( 'wp-2fa-remove-user-2fa-nonce' ); ?>"><?php esc_html_e( 'Yes', 'wp-2fa' ); ?></a>
341 <button class="modal__btn" data-micromodal-close aria-label="Close this dialog window"><?php esc_html_e( 'No', 'wp-2fa' ); ?></button>
342 </footer>
343 </div>
344 </div>
345 </div>
346 <div class="wp2fa-modal micromodal-slide" id="configure-2fa" aria-hidden="true">
347 <div class="modal__overlay" tabindex="-1" data-micromodal-close>
348 <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
349 <header class="modal__header">
350 <button class="modal__close" aria-label="Close modal" data-micromodal-close></button>
351 </header>
352 <main class="modal__content" id="modal-1-content">
353 <?php
354 // Grab current user
355 $user = wp_get_current_user();
356
357 // Grab key from user meta
358 $key = Authentication::get_user_totp_key( $user->ID );
359
360 // If no key is present, lets make one
361 if ( empty( $key ) ) {
362 $key = Authentication::generate_key();
363 $update = update_user_meta( $user->ID, 'wp_2fa_totp_key', $key );
364 }
365
366 // Setup site information, used when generating our QR code
367 $site_name = get_bloginfo( 'name', 'display' );
368 $totp_title = apply_filters( 'wp_2fa_totp_title', $site_name . ':' . $user->user_login, $user );
369
370 // Now lets grab the users enabled 2fa methods.
371 $selected_method = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
372
373 // Create a nonce incase we want to reset the key
374 $nonce = wp_create_nonce( 'wp-2fa-backup-codes-generate-json-' . $user->ID );
375 $validate_nonce = wp_create_nonce( 'wp-2fa-validate-authcode' );
376 ?>
377
378 <div class="wizard-step active">
379 <fieldset>
380 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'enable_totp' ) ) ) { ?>
381 <div class="option-pill">
382 <h3>
383 <?php esc_html_e( 'Reconfigure the 2FA App', 'wp-2fa' ); ?>
384 </h3>
385 <p>
386 <?php esc_html_e( 'Click the below button to reconfigure the current 2FA method. Note that once reset 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' ); ?>
387 </p>
388 <div class="wp2fa-setup-actions">
389 <a href="#" class="button button-primary" name="next_step_setting_modal_wizard" data-trigger-reset-key="no-reload" data-nonce="<?php echo esc_attr( $nonce ); ?>" data-user-id="<?php echo esc_attr( $user->ID ); ?>" data-next-step="2fa-wizard-totp"><?php esc_html_e( 'Reset Key', 'wp-2fa' ); ?></a>
390 </div>
391 </div>
392 <?php } ?>
393 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'enable_email' ) ) ) {
394 $setupnonce = wp_create_nonce( 'wp-2fa-send-setup-email' );
395 ?>
396 <br>
397 <div class="option-pill">
398 <h3><?php esc_html_e( 'Setup the 2FA method', 'wp-2fa' ); ?></h3>
399 <p>
400 <?php esc_html_e( 'Please select the email address where the one-time code should be sent:', 'wp-2fa' ); ?>
401 </p>
402 <fieldset>
403 <label for="use_wp_email">
404 <span><?php esc_html_e( 'Type in below the new email address where you want to receive the 2FA one-time codes.', 'wp-2fa' ); ?></span>
405 <br><br>
406 <input type="email" name="custom-email-address" id="custom-email-address" class="input wide" value=""/>
407 </label>
408 </fieldset>
409 <div class="wp2fa-setup-actions">
410 <a class="button button-primary" name="next_step_setting_modal_wizard" value="<?php esc_attr_e( 'I\'m Ready', 'wp-2fa' ); ?>" data-trigger-setup-email data-user-id="<?php echo esc_attr( $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>
411 </div>
412 </div>
413 <?php } ?>
414 </fieldset>
415 </div>
416
417 <div class="wizard-step" id="2fa-wizard-totp">
418 <fieldset>
419
420 <div class="step-setting-wrapper active">
421 <h3><?php esc_html_e( 'Setup the 2FA method', 'wp-2fa' ); ?></h3>
422 <div class="option-pill">
423 <ol>
424 <li><?php esc_html_e( 'Download the Google Authenticator app', 'wp-2fa' ); ?></li>
425 <li><?php esc_html_e( 'Click the plus sign (add new icon)', 'wp-2fa' ); ?></li>
426 <li><?php esc_html_e( 'Select \'Scan a barcode\'', 'wp-2fa' ); ?></li>
427 <li><?php esc_html_e( 'Scan the QR code to the right.', 'wp-2fa' ); ?></li>
428 </ol>
429 <p><?php esc_html_e( 'Otherwise, select Enter a provided key and type in the key below:', 'wp-2fa' ); ?></p>
430 <code><?php echo esc_html( $key ); ?></code>
431 </div>
432 <img style="right: 21px; position: absolute; top: 103px;" src="<?php echo esc_url( Authentication::get_google_qr_code( $totp_title, $key, $site_name ) ); ?>" id="wp-2fa-totp-qrcode" />
433 <br>
434 <div class="wp2fa-setup-actions">
435 <br>
436 <a class="button button-primary" name="next_step_setting"><?php esc_html_e( 'I\'m Ready', 'wp-2fa' ); ?></a>
437 </div>
438 </div>
439
440 <div class="step-setting-wrapper">
441 <h3><?php esc_html_e( 'Almost there…', 'wp-2fa' ); ?></h3>
442 <p><?php esc_html_e( 'Please type in the one-time code from your Google Authenticator app to finalize the setup.', 'wp-2fa' ); ?></p>
443 <br>
444 <fieldset>
445 <label for="2fa-totp-authcode">
446 <?php esc_html_e( 'Authentication Code:', 'wp-2fa' ); ?>
447 <input type="tel" name="wp-2fa-totp-authcode" id="wp-2fa-totp-authcode" class="input" value="" size="20" pattern="[0-9]*" />
448 </label>
449 <div class="verification-response"></div>
450 </fieldset>
451 <br>
452 <input type="hidden" name="wp-2fa-totp-key" value="<?php echo esc_attr( $key ); ?>" />
453
454 <a href="#" class="modal__btn modal__btn-primary button" data-validate-authcode-ajax data-nonce="<?php echo esc_attr( $validate_nonce ); ?>"><?php esc_html_e( 'Validate & Save Configuration', 'wp-2fa' ); ?></a>
455 <button class="modal__btn" data-micromodal-close aria-label="Close this dialog window"><?php esc_html_e( 'Cancel', 'wp-2fa' ); ?></button>
456 </div>
457
458 </fieldset>
459 </div>
460
461 <div class="wizard-step" id="2fa-wizard-email">
462 <fieldset>
463
464 <div class="step-setting-wrapper active">
465 <h4><?php esc_html_e( 'Almost there…', 'wp-2fa' ); ?></h4>
466 <p><?php esc_html_e( 'Please type in the one-time code sent to your email address to finalize the setup.', 'wp-2fa' ); ?></p>
467 <br>
468 <fieldset>
469 <label for="2fa-email-authcode">
470 <?php esc_html_e( 'Authentication Code:', 'wp-2fa' ); ?>
471 <input type="tel" name="wp-2fa-email-authcode" id="wp-2fa-email-authcode" class="input" value="" size="20" pattern="[0-9]*" />
472 </label>
473 <div class="verification-response"></div>
474 </fieldset>
475
476 <input type="hidden" name="wp-2fa-totp-key" value="<?php echo esc_attr( $key ); ?>" />
477 </div>
478 <br>
479 <a href="#" class="modal__btn modal__btn-primary button" data-validate-authcode-ajax data-nonce="<?php echo esc_attr( $validate_nonce ); ?>"><?php esc_html_e( 'Validate Code', 'wp-2fa' ); ?></a>
480 <button class="modal__btn" data-micromodal-close aria-label="Close this dialog window"><?php esc_html_e( 'Cancel', 'wp-2fa' ); ?></button>
481 </fieldset>
482 </div>
483
484 <div class="wizard-step" id="2fa-wizard-setup-done">
485 <fieldset>
486
487 <h3><?php esc_html_e( 'Your website just got more secure!', 'wp-2fa' ); ?></h3>
488 <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>
489
490 <p><?php esc_html_e( 'You can exit this wizard now or continue to configure the plugin’s general settings. ', 'wp-2fa' ); ?></p>
491
492 <p class="description"><?php esc_html_e( 'Note: all the settings can be configured from the Settings > Two-factor Authentication entry of your WordPress menu.', 'wp-2fa' ); ?></p>
493
494 </fieldset>
495 <a href="#" class="modal__btn modal__btn-primary button" name="next_step_setting_modal_wizard" data-next-step><?php esc_html_e( 'Next Step', 'wp-2fa' ); ?></a>
496 <button class="modal__btn" data-micromodal-close aria-label="Close this dialog window"><?php esc_html_e( 'Close', 'wp-2fa' ); ?></button>
497 </div>
498 </main>
499 </div>
500 </div>
501 </div>
502
503 <div class="wp2fa-modal micromodal-slide" id="configure-2fa-backup-codes" aria-hidden="true">
504 <div class="modal__overlay" tabindex="-1" data-micromodal-close>
505 <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
506 <header class="modal__header">
507 <button class="modal__close" aria-label="Close modal" data-micromodal-close></button>
508 </header>
509 <main class="modal__content" id="modal-1-content">
510 <?php
511 // Grab current user.
512 $user = wp_get_current_user();
513 // Create a nonce for use in ajax call to generate codes.
514 $nonce = wp_create_nonce( 'wp-2fa-backup-codes-generate-json-' . $user->ID );
515 ?>
516 <div class="step-setting-wrapper active">
517 <h3><?php esc_html_e( 'Generate backup codes', 'wp-2fa' ); ?></h3>
518 <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>
519
520 <div class="wp2fa-setup-actions">
521 <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 ); ?>" data-user-id="<?php echo esc_attr( $user->ID ); ?>">
522 <?php esc_html_e( 'Generate backup codes', 'wp-2fa' ); ?>
523 </button>
524 <a href="<?php echo esc_url( admin_url() ); ?>" class="button button-secondary" type="submit" name="save_step" value="<?php esc_attr_e( 'I’ll generate them later', 'wp-2fa' ); ?>">
525 <?php esc_html_e( 'I’ll generate them later', 'wp-2fa' ); ?>
526 </a>
527 </div>
528 </div>
529
530 <div class="step-setting-wrapper align-center">
531 <h3><?php esc_html_e( 'Backup codes generated', 'wp-2fa' ); ?></h3>
532 <p><?php esc_html_e( 'Here are your backup codes:', 'wp-2fa' ); ?></p>
533 <code id="backup-codes-wrapper"></code>
534 <div class="wp2fa-setup-actions">
535 <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( $user->display_name ); ?>" data-website-url="<?php echo esc_attr( get_home_url() ); ?>">
536 <?php esc_html_e( 'Download', 'wp-2fa' ); ?>
537 </button>
538 <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( $user->display_name ); ?>" data-website-url="<?php echo esc_attr( get_home_url() ); ?>">
539 <?php esc_html_e( 'Print', 'wp-2fa' ); ?>
540 </button>
541 </div>
542 </div>
543
544 </main>
545 </div>
546 </div>
547 </div>
548 </div>
549 </td>
550 </tr>
551 </tbody>
552 </table>
553 <?php
554
555 } else {
556 ?>
557 <?php if ( ! isset( $is_shortcode ) && ! $is_shortcode === 'output_shortcode' ) : ?>
558 <h2>
559 <?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?>
560 </h2>
561 <?php endif; ?>
562 <?php
563 $class = 'notice notice-info wp-2fa-nag';
564 $grace_expiry = get_user_meta( $user->ID, 'wp_2fa_grace_period_expiry', true );
565 $reconfigure_2fa = get_user_meta( $user->ID, 'wp_2fa_user_needs_to_reconfigure_2fa', true );
566 if ( $reconfigure_2fa ) {
567 $message = esc_html__( 'The 2FA method you were using is no longer allowed on this website. Please reconfigure 2FA using one of the supported methods within', 'wp-2fa' );
568 } else {
569 $message = esc_html__( 'This website’s administrator requires you to enable 2FA authentication within', 'wp-2fa' );
570 }
571
572 ?>
573 <?php if ( 'true' === $show_preamble ) { ?>
574 <?php if ( ! empty( $grace_expiry ) && ! get_user_meta( $user->ID, 'wp_2fa_user_enforced_instantly', true ) ) { ?>
575 <p class="description">
576 <?php echo $message; ?> <span class="grace-period-countdown" data-countdown-timestamp="<?php echo esc_attr( $grace_expiry ); ?>"></span>
577 </p>
578 <?php } ?>
579 <?php if ( get_user_meta( $user->ID, 'wp_2fa_user_enforced_instantly', true ) ) { ?>
580 <p class="description">
581 <?php echo esc_html__( 'This website’s administrator requires you to enable 2FA authentication to continue.', 'wp-2fa' ); ?>
582 </p>
583 <?php } ?>
584 <p class="description">
585 <?php esc_html_e( 'Add two-factor authentication to strengthen the security of your WordPress user account.', 'wp-2fa' ); ?>
586 </p>
587 <?php } ?>
588 <table class="form-table" role="presentation">
589 <tbody>
590 <tr>
591 <th>
592 <label>
593 <?php esc_html_e( '2-Factor authentication', 'wp-2fa' ); ?>
594 </label>
595 </th>
596
597 <td>
598 <a href="#" class="button button-primary remove-2fa" onclick="MicroModal.show('configure-2fa',{
599 onShow: modal => jQuery( '.wizard-step:first-of-type' ).addClass( 'active' ),
600 onClose: modal => jQuery( '.wizard-step.active' ).removeClass( 'active' ),
601 });"><?php esc_html_e( 'Configure 2FA', 'wp-2fa' ); ?></a>
602
603 <div>
604 <div class="wp2fa-modal micromodal-slide" id="configure-2fa" aria-hidden="true">
605 <div class="modal__overlay" tabindex="-1" data-micromodal-close>
606 <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
607 <header class="modal__header">
608 <button class="modal__close" aria-label="Close modal" data-micromodal-close></button>
609 </header>
610 <main class="modal__content" id="modal-1-content">
611 <?php
612 $user = wp_get_current_user();
613 $enabled_method = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
614
615 // Grab key from user meta.
616 $key = Authentication::get_user_totp_key( $user->ID );
617
618 // If no key is present, lets make one.
619 if ( empty( $key ) ) {
620 $key = Authentication::generate_key();
621 $update = update_user_meta( $user->ID, 'wp_2fa_totp_key', $key );
622 }
623 $setupnonce = wp_create_nonce( 'wp-2fa-send-setup-email' );
624 $validate_nonce = wp_create_nonce( 'wp-2fa-validate-authcode' );
625
626 // Setup site information, used when generating our QR code.
627 $site_name = get_bloginfo( 'name', 'display' );
628 $totp_title = apply_filters( 'wp_2fa_totp_title', $site_name . ':' . $user->user_login, $user );
629
630 if ( ! empty( WP2FA::get_wp2fa_setting( 'enable_totp' ) ) && ! empty( WP2FA::get_wp2fa_setting( 'enable_email' ) ) ) {
631 $intro_text = esc_html__( 'Choose the 2FA authentication method', 'wp-2fa' );
632 $sub_text = esc_html__( 'There are two methods available from which you can choose for 2FA:', 'wp-2fa' );
633 } else {
634 $intro_text = esc_html__( 'Choose the 2FA authentication method', 'wp-2fa' );
635 $sub_text = esc_html__( 'Only the below 2FA method is allowed on this website:', 'wp-2fa' );
636 }
637 ?>
638
639 <div class="wizard-step active">
640 <h3><?php echo sanitize_text_field( $intro_text ); ?></h3>
641 <p><?php echo sanitize_text_field( $sub_text ); ?></p>
642
643 <br>
644
645 <fieldset>
646 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'enable_totp' ) ) ) { ?>
647 <div class="option-pill">
648 <label for="basic">
649 <input id="basic" name="wp_2fa_enabled_methods" type="radio" value="totp" checked>
650 <?php esc_html_e( 'One-time code generated with your app of choice (most reliable and secure)', 'wp-2fa' ); ?>
651 </label>
652 <?php
653 printf( '<p class="description">%1$s <a href="https://www.wpwhitesecurity.com/support/kb/configuring-2fa-apps/" target="_blank">%2$s</a> %3$s</p>', esc_html__( 'Note: This method requires you to install one of the following 2FA apps: Google Authenticator, FreeOTP, Microsoft Authenticator, Duo Security, Authy and LastPass. All of these apps are free and can be downloaded from the Google Play and Apple Appstore. Read our guides on', 'wp-2fa' ), esc_html__( 'our knowledge base', 'wp-2fa' ), esc_html__( 'for more information on how to setup these apps.', 'wp-2fa' ) );
654 ?>
655 </div>
656 <?php } ?>
657 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'enable_email' ) ) ) { ?>
658 <br>
659 <div class="option-pill">
660 <label for="geek">
661 <input id="geek" name="wp_2fa_enabled_methods" type="radio" value="email">
662 <?php esc_html_e( 'One-time code sent to you over email', 'wp-2fa' ); ?>
663 </label>
664 </div>
665 <?php } ?>
666 </fieldset>
667 <br><br>
668 <a href="#" class="modal__btn modal__btn-primary button 2fa-choose-method" name="next_step_setting_modal_wizard" data-next-step><?php esc_html_e( 'Next Step', 'wp-2fa' ); ?></a>
669 <button class="modal__btn" data-micromodal-close aria-label="Close this dialog window"><?php esc_html_e( 'Close', 'wp-2fa' ); ?></button>
670 </div>
671
672 <div class="wizard-step" id="2fa-wizard-totp">
673 <fieldset>
674
675 <div class="step-setting-wrapper active">
676 <h3><?php esc_html_e( 'Setup the 2FA method', 'wp-2fa' ); ?></h3>
677 <div class="option-pill">
678 <ol>
679 <li><?php esc_html_e( 'Download the Google Authenticator app', 'wp-2fa' ); ?></li>
680 <li><?php esc_html_e( 'Click the plus sign (add new icon)', 'wp-2fa' ); ?></li>
681 <li><?php esc_html_e( 'Select \'Scan a barcode\'', 'wp-2fa' ); ?></li>
682 <li><?php esc_html_e( 'Scan the QR code to the right.', 'wp-2fa' ); ?></li>
683 </ol>
684 <p><?php esc_html_e( 'Otherwise, select Enter a provided key and type in the key below:', 'wp-2fa' ); ?></p>
685 <code><?php echo esc_html( $key ); ?></code>
686 </div>
687 <img style="right: 21px; position: absolute; top: 103px;" src="<?php echo esc_url( Authentication::get_google_qr_code( $totp_title, $key, $site_name ) ); ?>" id="wp-2fa-totp-qrcode" />
688 <br>
689 <div class="wp2fa-setup-actions">
690 <br>
691 <a class="button button-primary" name="next_step_setting"><?php esc_html_e( 'I\'m Ready', 'wp-2fa' ); ?></a>
692 </div>
693 </div>
694
695 <div class="step-setting-wrapper">
696 <h3><?php esc_html_e( 'Almost there…', 'wp-2fa' ); ?></h3>
697 <p><?php esc_html_e( 'Please type in the one-time code from your Google Authenticator app to finalize the setup.', 'wp-2fa' ); ?></p>
698 <br>
699 <fieldset>
700 <label for="2fa-totp-authcode">
701 <?php esc_html_e( 'Authentication Code:', 'wp-2fa' ); ?>
702 <input type="tel" name="wp-2fa-totp-authcode" id="wp-2fa-totp-authcode" class="input" value="" size="20" pattern="[0-9]*" />
703 </label>
704 <div class="verification-response"></div>
705 </fieldset>
706 <input type="hidden" name="wp-2fa-totp-key" value="<?php echo esc_attr( $key ); ?>" />
707 <br>
708 <a href="#" class="modal__btn modal__btn-primary button" data-validate-authcode-ajax data-nonce="<?php echo esc_attr( $validate_nonce ); ?>"><?php esc_html_e( 'Validate & Save Configuration', 'wp-2fa' ); ?></a>
709 <button class="modal__btn" data-micromodal-close aria-label="Close this dialog window"><?php esc_html_e( 'Cancel', 'wp-2fa' ); ?></button>
710 </div>
711
712 </fieldset>
713 </div>
714
715 <div class="wizard-step" id="2fa-wizard-email">
716 <fieldset>
717 <div class="step-setting-wrapper active">
718 <h3><?php esc_html_e( 'Setup the 2FA method', 'wp-2fa' ); ?></h3>
719 <p>
720 <?php esc_html_e( 'Please select the email address where the one-time code should be sent:', 'wp-2fa' ); ?>
721 </p>
722 <fieldset>
723 <label for="use_wp_email">
724 <input type="radio" name="wp_2fa_email_address" id="use_wp_email" value="<?php echo esc_attr( $user->user_email ); ?>" checked>
725 <span><?php esc_html_e( 'Use my WordPress user email (', 'wp-2fa' ); ?><small><?php echo esc_attr( $user->user_email ); ?></small><?php esc_html_e( ')', 'wp-2fa' ); ?></span>
726 </label>
727 <br/>
728 <label for="use_custom_email">
729 <input type="radio" name="wp_2fa_email_address" id="use_custom_email" value="use_custom_email">
730 <span><?php esc_html_e( 'Use a different email address:', 'wp-2fa' ); ?></span>
731 <input type="email" name="custom-email-address" id="custom-email-address" class="input wide" value=""/>
732 </label>
733 </fieldset>
734 <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>
735 <div class="wp2fa-setup-actions">
736 <a class="button button-primary" name="next_step_setting" value="<?php esc_attr_e( 'I\'m Ready', 'wp-2fa' ); ?>" data-trigger-setup-email data-user-id="<?php echo esc_attr( $user->ID ); ?>" data-nonce="<?php echo esc_attr( $setupnonce ); ?>" data-next-step="2fa-wizard-email"><?php esc_html_e( 'I\'m Ready', 'wp-2fa' ); ?></a>
737 </div>
738 </div>
739
740 <div class="step-setting-wrapper" id="2fa-wizard-email">
741 <h4><?php esc_html_e( 'Almost there…', 'wp-2fa' ); ?></h4>
742 <p><?php esc_html_e( 'Please type in the one-time code sent to your email address to finalize the setup.', 'wp-2fa' ); ?></p>
743 <fieldset>
744 <label for="2fa-email-authcode">
745 <?php esc_html_e( 'Authentication Code:', 'wp-2fa' ); ?>
746 <input type="tel" name="wp-2fa-email-authcode" id="wp-2fa-email-authcode" class="input" value="" size="20" pattern="[0-9]*" />
747 </label>
748 <div class="verification-response"></div>
749 </fieldset>
750 <input type="hidden" name="wp-2fa-totp-key" value="<?php echo esc_attr( $key ); ?>" />
751
752 <a href="#" class="modal__btn modal__btn-primary button" data-validate-authcode-ajax data-nonce="<?php echo esc_attr( $validate_nonce ); ?>"><?php esc_html_e( 'Validate & Save Configuration', 'wp-2fa' ); ?></a>
753 <button class="modal__btn" data-micromodal-close aria-label="Close this dialog window"><?php esc_html_e( 'Cancel', 'wp-2fa' ); ?></button>
754 </div>
755 </fieldset>
756 </div>
757
758 <div class="wizard-step" id="2fa-wizard-config-backup-codes">
759 <?php
760 // Grab current user.
761 $user = wp_get_current_user();
762 // Create a nonce for use in ajax call to generate codes.
763 $nonce = wp_create_nonce( 'wp-2fa-backup-codes-generate-json-' . $user->ID );
764 ?>
765 <div class="step-setting-wrapper active">
766 <h3><?php esc_html_e( 'Generate backup codes', 'wp-2fa' ); ?></h3>
767 <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>
768
769 <div class="wp2fa-setup-actions">
770 <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 ); ?>" data-user-id="<?php echo esc_attr( $user->ID ); ?>">
771 <?php esc_html_e( 'Generate backup codes', 'wp-2fa' ); ?>
772 </button>
773 <a href="#" class="button button-secondary" name="save_step" value="<?php esc_attr_e( 'I’ll generate them later', 'wp-2fa' ); ?>">
774 <?php esc_html_e( 'I’ll generate them later', 'wp-2fa' ); ?>
775 </a>
776 </div>
777 </div>
778
779 <div class="step-setting-wrapper align-center">
780 <h3><?php esc_html_e( 'Backup codes generated', 'wp-2fa' ); ?></h3>
781 <p><?php esc_html_e( 'Here are your backup codes:', 'wp-2fa' ); ?></p>
782 <code id="backup-codes-wrapper"></code>
783 <div class="wp2fa-setup-actions">
784 <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( $user->display_name ); ?>" data-website-url="<?php echo esc_attr( get_home_url() ); ?>">
785 <?php esc_html_e( 'Download', 'wp-2fa' ); ?>
786 </button>
787 <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( $user->display_name ); ?>" data-website-url="<?php echo esc_attr( get_home_url() ); ?>">
788 <?php esc_html_e( 'Print', 'wp-2fa' ); ?>
789 </button>
790 <button class="modal__btn" data-micromodal-close aria-label="Close this dialog window"><?php esc_html_e( 'Close wizard & refresh', 'wp-2fa' ); ?></button>
791 </div>
792 </div>
793 </div>
794 </main>
795 </div>
796 </div>
797 </div>
798 </div>
799 </td>
800 </tr>
801 </tbody>
802 </table>
803 <?php
804
805 }
806
807 } elseif ( $is_user_excluded ) {
808 ?>
809 <?php if ( ! isset( $is_shortcode ) && ! $is_shortcode === 'output_shortcode' ) : ?>
810 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
811 <?php endif; ?>
812 <?php if ( 'true' === $show_preamble ) { ?>
813 <p class="description"><?php esc_html_e( 'Add two-factor authentication to strengthen the security of your WordPress user account.', 'wp-2fa' ); ?></p>
814 <p class="description"><?php esc_html_e( 'Your user / role is not permitted to configure 2FA. Contact your administrator for more information.', 'wp-2fa' ); ?></p>
815 <?php } ?>
816 <?php
817
818 } elseif ( $grace_period_expired && current_user_can( 'manage_options' ) ) {
819 ?>
820 <?php if ( ! isset( $is_shortcode ) && ! $is_shortcode === 'output_shortcode' ) : ?>
821 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
822 <?php endif; ?>
823 <table class="form-table" role="presentation">
824 <tbody>
825 <tr>
826 <th><label><?php esc_html_e( '2-Factor authentication', 'wp-2fa' ); ?></label></th>
827 <td>
828 <?php
829 $url = add_query_arg(
830 array(
831 'action' => 'unlock_account',
832 'user_id' => $user->ID,
833 'wp_2fa_nonce' => wp_create_nonce( 'wp-2fa-unlock-account-nonce' ),
834 ),
835 admin_url( 'user-edit.php' )
836 );
837
838 if ( $grace_period_expired ) {
839 ?>
840 <a href="<?php echo esc_url( $url ); ?>" class="button button-primary"><?php esc_html_e( 'Unlock user and reset the grace period', 'wp-2fa' ); ?></a>
841 <?php
842 }
843 ?>
844 </td>
845 </tr>
846 </tbody>
847 </table>
848 <?php
849 } elseif ( ! $grace_period_expired && current_user_can( 'manage_options' ) && ! empty( $enabled_methods ) ) {
850 ?>
851 <?php if ( ! isset( $is_shortcode ) && ! $is_shortcode === 'output_shortcode' ) : ?>
852 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
853 <?php endif; ?>
854 <p class="description"><?php esc_html_e( 'By resetting this user\'s 2FA configuration you disable the currently configured 2FA so the user can log back in using a usemame and a password only. *the user if enforced to setup 2FA the user will get a prompt upon logging in, from where 2FA can be configured. The user has to configure 2FA within the configured grace period.', 'wp-2fa' ); ?></p>
855 <table class="form-table" role="presentation">
856 <tbody>
857 <tr>
858 <th><label><?php esc_html_e( '2-Factor authentication', 'wp-2fa' ); ?></label></th>
859 <td>
860 <?php
861 // Create remove 2fa link.
862 $url = add_query_arg(
863 array(
864 'action' => 'remove_user_2fa',
865 'user_id' => $user->ID,
866 'wp_2fa_nonce' => wp_create_nonce( 'wp-2fa-remove-user-2fa-nonce' ),
867 'admin_reset' => 'yes',
868 ),
869 admin_url( 'user-edit.php' )
870 );
871 ?>
872 <a href="<?php echo esc_url( $url ); ?>" class="button button-primary"><?php esc_html_e( 'Reset 2FA configuration', 'wp-2fa' ); ?></a>
873 </td>
874 </tr>
875 </tbody>
876 </table>
877 <?php
878 }
879 }
880
881 /**
882 * Add custom unlock account link to user edit admin list.
883 *
884 * @param string $actions Default actions.
885 * @param object $user_object User data.
886 * @return string Appended actions.
887 */
888 public function user_2fa_row_actions( $actions, $user_object ) {
889 $nonce = wp_create_nonce( 'wp-2fa-unlock-account-nonce' );
890 $grace_period_expired = get_user_meta( $user_object->ID, 'wp_2fa_user_grace_period_expired', true );
891 $url = add_query_arg(
892 array(
893 'action' => 'unlock_account',
894 'user_id' => $user_object->ID,
895 'wp_2fa_nonce' => $nonce,
896 ),
897 admin_url( 'users.php' )
898 );
899
900 if ( $grace_period_expired ) {
901 $actions['edit_badges'] = '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Unlock user', 'wp-2fa' ) . '</a>';
902 }
903 return $actions;
904 }
905
906 /**
907 * Save user profile information.
908 */
909 public function save_user_2fa_options( $input ) {
910
911 // Ensure we have the inputs we want before we process.
912 // To avoid causing issues with the rest of the user profile.
913 if ( ! is_array( $input ) ) {
914 return;
915 }
916
917 // Assign the input to post, in case we are dealing with saving the data from another page.
918 if ( isset( $input ) ) {
919 $_POST = $input;
920 } else {
921 $_POST = $_POST;
922 }
923
924 // Grab current user.
925 $user = wp_get_current_user();
926
927 // Setup some empty arrays which will may fill later, should an error arise along the way.
928 $notices = array();
929 $errors = array();
930
931 // Grab key from the $_POST.
932 if ( isset( $_POST['wp-2fa-totp-key'] ) ) {
933 $current_key = sanitize_text_field( wp_unslash( $_POST['wp-2fa-totp-key'] ) );
934 }
935
936 // Grab authcode and ensure its a number.
937 if ( isset( $_POST['wp-2fa-totp-authcode'] ) ) {
938 $_POST['wp-2fa-totp-authcode'] = (int) $_POST['wp-2fa-totp-authcode'];
939 }
940
941 if ( ! isset( $_POST['custom-email-address'] ) || isset( $_POST['custom-email-address'] ) && empty( $_POST['custom-email-address'] ) ) {
942 if ( isset( $_POST['email'] ) ) {
943 update_user_meta( $user->ID, 'wp_2fa_nominated_email_address', $_POST['email'] );
944 } elseif ( isset( $_POST['wp_2fa_email_address'] ) ) {
945 update_user_meta( $user->ID, 'wp_2fa_nominated_email_address', $_POST['wp_2fa_email_address'] );
946 }
947
948 } elseif ( isset( $_POST['custom-email-address'] ) ) {
949 update_user_meta( $user->ID, 'wp_2fa_nominated_email_address', sanitize_email( wp_unslash( $_POST['custom-email-address'] ) ) );
950 }
951
952 // Now lets grab the users enabled 2fa methods.
953 $get_array = filter_input_array( INPUT_GET );
954 $selected_method = sanitize_text_field( $get_array['enabled_methods'] );
955 // Check its one of our options.
956 if ( isset( $_POST['wp_2fa_enabled_methods'] ) && 'totp' === $_POST['wp_2fa_enabled_methods'] || isset( $_POST['wp_2fa_enabled_methods'] ) && 'email' === $_POST['wp_2fa_enabled_methods'] ) {
957 update_user_meta( $user->ID, 'wp_2fa_enabled_methods', sanitize_text_field( wp_unslash( $_POST['wp_2fa_enabled_methods'] ) ) );
958 delete_user_meta( $user->ID, 'wp_2fa_grace_period_expiry' );
959 delete_user_meta( $user->ID, 'wp_2fa_user_enforced_instantly' );
960 }
961
962 if ( isset( $_POST['wp-2fa-email-authcode'] ) && ! empty( $_POST['wp-2fa-email-authcode'] ) ) {
963 update_user_meta( $user->ID, 'wp_2fa_enabled_methods', 'email' );
964 delete_user_meta( $user->ID, 'wp_2fa_grace_period_expiry' );
965 delete_user_meta( $user->ID, 'wp_2fa_user_enforced_instantly' );
966 }
967
968 if ( isset( $_POST['wp-2fa-totp-authcode'] ) && ! empty( $_POST['wp-2fa-totp-authcode'] ) ) {
969 update_user_meta( $user->ID, 'wp_2fa_enabled_methods', 'totp' );
970 delete_user_meta( $user->ID, 'wp_2fa_grace_period_expiry' );
971 delete_user_meta( $user->ID, 'wp_2fa_user_enforced_instantly' );
972 }
973 }
974
975 /**
976 * Validate a user's code when setting up 2fa via the inline form.
977 *
978 * @return json result of validation.
979 */
980 public function validate_authcode_via_ajax() {
981 check_ajax_referer( 'wp-2fa-validate-authcode' );
982
983 if ( isset( $_POST['form'] ) ) {
984 $input = $_POST['form'];
985 } else {
986 return 'No form';
987 }
988
989 $user = wp_get_current_user();
990
991 // Setup some empty arrays which will may fill later, should an error arise along the way.
992 $notices = array();
993 $our_errors = '';
994
995 // Grab key from the $_POST.
996 if ( isset( $input['wp-2fa-totp-key'] ) ) {
997 $current_key = sanitize_text_field( wp_unslash( $input['wp-2fa-totp-key'] ) );
998 }
999
1000 // Grab authcode and ensure its a number.
1001 if ( isset( $input['wp-2fa-totp-authcode'] ) ) {
1002 $input['wp-2fa-totp-authcode'] = (int) $input['wp-2fa-totp-authcode'];
1003 }
1004
1005 // Check if we are dealing with totp or email, if totp validate and store a new secret key.
1006 if ( ! empty( $input['wp-2fa-totp-authcode'] ) && ! empty( $current_key ) ) {
1007 if ( Authentication::is_valid_key( $current_key ) || ! is_numeric( $input['wp-2fa-totp-authcode'] ) ) {
1008 if ( ! Authentication::is_valid_authcode( $current_key, sanitize_text_field( wp_unslash( $input['wp-2fa-totp-authcode'] ) ) ) ) {
1009 $our_errors = esc_html__( 'Invalid Two Factor Authentication code.', 'wp-2fa' );
1010 }
1011 } else {
1012 $our_errors = esc_html__( 'Invalid Two Factor Authentication secret key.', 'wp-2fa' );
1013 }
1014
1015 // If its not totp, is it email.
1016 } elseif ( ! empty( $input['wp-2fa-email-authcode'] ) ) {
1017 if ( ! Authentication::validate_token( $user->ID, sanitize_text_field( wp_unslash( $input['wp-2fa-email-authcode'] ) ) ) ) {
1018 $our_errors = __( 'Invalid Email Authentication code.', 'wp-2fa' );
1019 }
1020 } else {
1021 $our_errors = __( 'Please enter the code to finalize the 2FA setup.', 'wp-2fa' );
1022 }
1023
1024 if ( ! empty( $our_errors ) ) {
1025 // Send the response.
1026 wp_send_json_error(
1027 array(
1028 'error' => $our_errors,
1029 )
1030 );
1031 } else {
1032 $this->save_user_2fa_options( $input );
1033 // Send the response.
1034 wp_send_json_success();
1035 }
1036 }
1037 }
1038