PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 1.3.0
WP 2FA – Two-factor authentication for WordPress v1.3.0
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 / SettingsPage.php
wp-2fa / includes / classes / Admin Last commit date
SettingsPage.php 6 years ago SetupWizard.php 6 years ago UserNotices.php 6 years ago UserProfile.php 6 years ago UserRegistered.php 6 years ago
SettingsPage.php
1751 lines
1 <?php // phpcs:ignore
2
3 namespace WP2FA\Admin;
4
5 use \WP2FA\WP2FA as WP2FA;
6 use \WP2FA\Authenticator\Authentication as Authentication;
7
8 /**
9 * SettingsPage - Class for handling settings
10 */
11 class SettingsPage {
12
13 /**
14 * Create admin menu entru and settings page
15 */
16 public function create_settings_admin_menu() {
17 // Create sub menu item.
18 add_options_page(
19 esc_html__( 'WP 2FA Settings', 'wp-2fa' ),
20 esc_html__( 'Two-factor Authentication', 'wp-2fa' ),
21 'manage_options',
22 'wp-2fa-settings',
23 array( $this, 'settings_page_render' )
24 );
25
26 // Register our settings page.
27 register_setting(
28 'wp_2fa_settings',
29 'wp_2fa_settings',
30 array( $this, 'validate_and_sanitize' )
31 );
32
33 register_setting(
34 'wp_2fa_email_settings',
35 'wp_2fa_email_settings',
36 array( $this, 'validate_and_sanitize_email' )
37 );
38 }
39
40 /**
41 * Create admin menu entru and settings page
42 */
43 public function create_settings_admin_menu_multisite() {
44 // Create sub menu item.
45 add_submenu_page(
46 'settings.php',
47 esc_html__( 'WP 2FA Settings', 'wp-2fa' ),
48 esc_html__( 'Two-factor Authentication', 'wp-2fa' ),
49 'manage_options',
50 'wp-2fa-settings',
51 array( $this, 'settings_page_render' )
52 );
53 // Register our settings page.
54 register_setting(
55 'wp_2fa_settings',
56 'wp_2fa_settings',
57 array( $this, 'validate_and_sanitize' )
58 );
59
60 register_setting(
61 'wp_2fa_email_settings',
62 'wp_2fa_email_settings',
63 array( $this, 'validate_and_sanitize_email' )
64 );
65 }
66
67 /**
68 * Render the settings
69 */
70 public function settings_page_render() {
71 $user = wp_get_current_user();
72 $user_id = (int) $user->ID;
73 if ( ! empty( WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' ) ) ) {
74 $main_user = (int) WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' );
75 } else {
76 $main_user = '';
77 }
78
79 // Check if new user page has been published.
80 if ( ! empty( get_transient( 'wp_2fa_new_custom_page_created' ) ) ) {
81 $new_page_id = WP2FA::get_wp2fa_setting( 'custom-user-page-id' );
82 $new_page_permalink = get_permalink( $new_page_id );
83 ?>
84 <div class="wp2fa-modal micromodal-slide" id="new-page-created" aria-hidden="false">
85 <div class="modal__overlay" tabindex="-1" data-micromodal-close>
86 <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
87 <main class="modal__content" id="modal-1-content">
88 <h3><?php esc_html_e( 'The plugin created the 2FA settings page with the URL:', 'wp-2fa' ); ?></h3>
89 <h4>
90 <a target="_blank" href="<?php echo esc_url( $new_page_permalink ); ?>"><?php echo esc_attr( $new_page_permalink ); ?></a>
91 </h4>
92 <p>
93 <?php esc_html_e( 'You can edit this page using the page editor, like you do with all other pages.', 'wp-2fa' ); ?>
94 </p>
95 </main>
96 <footer class="modal__footer">
97 <a href="#" class="modal__btn modal__btn-primary" data-trigger-remove-new-page-notice onclick="MicroModal.close('new-page-created');"><?php esc_html_e( 'OK', 'wp-2fa' ); ?></a>
98 </footer>
99 </div>
100 </div>
101 </div>
102 <script>
103 MicroModal.show('new-page-created');
104 </script>
105 <?php
106 }
107 ?>
108 <div class="wrap">
109 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
110 <hr>
111 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'limit_access' ) ) && $main_user !== $user->ID ) { ?>
112
113 <?php
114 echo esc_html__( 'These settings have been disabled by your site administrator, please contact them for further assistance.', 'wp-2fa' );
115 ?>
116
117 <?php } else { ?>
118
119 <div class="nav-tab-wrapper">
120 <a href="<?php echo esc_url( add_query_arg( array( 'page' => 'wp-2fa-settings' ), network_admin_url( 'admin.php' ) ) ); ?>" class="nav-tab <?php echo ! isset( $_REQUEST['tab'] ) ? 'nav-tab-active' : ''; ?>"><?php _e( '2FA Settings', 'wp-2fa' ); ?></a>
121 <a href="<?php echo esc_url( add_query_arg( array( 'page' => 'wp-2fa-settings', 'tab' => 'email-settings' ), network_admin_url( 'admin.php' ) ) ); ?>" class="nav-tab <?php echo isset( $_REQUEST['tab'] ) && 'email-settings' === $_REQUEST['tab'] ? 'nav-tab-active' : ''; ?>"><?php _e( 'Email Settings & Templates', 'wp-2fa' ); ?></a>
122 </div>
123 <?php
124 if ( ! current_user_can( 'manage_options' ) ) {
125 return;
126 }
127 if ( WP2FA::is_this_multisite() ) {
128 $action = 'edit.php?action=update_wp2fa_network_options';
129 } else {
130 $action = 'options.php';
131 }
132 if ( ! isset( $_REQUEST['tab'] ) || isset( $_REQUEST['tab'] ) && '2fa-settings' === $_REQUEST['tab'] ) : ?>
133 <br/>
134 <?php
135 printf( '<p class="description">%1$s <a href="mailto:support@wpwhitesecurity.com">%2$s</a></p>', esc_html__( 'Use the settings below to configure the properties of the two-factor authentication on your website and how users use it. If you have any questions send us an email at', 'wp-2fa' ), esc_html__( 'support@wpwhitesecurity.com', 'wp-2fa' ) );
136 ?>
137 <br/>
138 <form action='<?php echo esc_attr( $action ) ?>' method='post' autocomplete="off">
139 <?php
140 if ( ! current_user_can( 'manage_options' ) ) {
141 return;
142 }
143
144 settings_fields( 'wp_2fa_settings' );
145 $this->select_method_setting();
146 $this->select_enforcment_policy_setting();
147 $this->user_profile_settings();
148 $this->excluded_roles_or_users_setting();
149 if ( WP2FA::is_this_multisite() ) {
150 $this->excluded_network_sites();
151 }
152 $this->grace_period_setting();
153 $this->limit_settings_access();
154 $this->remove_data_upon_uninstall();
155 submit_button();
156 ?>
157 </form>
158 <?php endif; ?>
159
160 <?php
161 if ( WP2FA::is_this_multisite() ) {
162 $action = 'edit.php?action=update_wp2fa_network_email_options';
163 } else {
164 $action = 'options.php';
165 }
166 ?>
167
168 <?php if ( isset( $_REQUEST['tab'] ) && 'email-settings' === $_REQUEST['tab'] ) : ?>
169 <br/>
170 <?php
171 printf( '<p class="description">%1$s <a href="mailto:support@wpwhitesecurity.com">%2$s</a></p>', esc_html__( 'Use the settings below to configure the emails which are sent to users as part of the 2FA plugin. If you have any questions send us an email at', 'wp-2fa' ), esc_html__( 'support@wpwhitesecurity.com', 'wp-2fa' ) );
172 ?>
173 <br/>
174 <form action='<?php echo esc_attr( $action ) ?>' method='post' autocomplete="off">
175 <?php
176 if ( ! current_user_can( 'manage_options' ) ) {
177 return;
178 }
179
180 settings_fields( 'wp_2fa_email_settings' );
181 $this->email_from_settings();
182 $this->email_settings();
183 submit_button( 'Save email settings and templates' );
184 ?>
185 </form>
186 <?php endif; ?>
187
188 <?php } ?>
189 </div>
190 <?php
191 }
192
193 /**
194 * General settings
195 */
196 private function select_method_setting() {
197 ?>
198 <h3><?php esc_html_e( 'Which two-factor authentication methods can your users use on this website?', 'wp-2fa' ); ?></h3>
199 <p class="description">
200 <?php esc_html_e( 'When you disable one of the below 2FA methods none of your users can use it.', 'wp-2fa' ); ?>
201 </p>
202 <table class="form-table">
203 <tbody>
204 <tr>
205 <th><label for="2fa-method"><?php esc_html_e( 'Select the methods:', 'wp-2fa' ); ?></label></th>
206 <td>
207 <fieldset>
208 <label for="totp">
209 <input type="checkbox" id="totp" name="wp_2fa_settings[enable_totp]" value="enable_totp"
210 <?php checked( 'enable_totp', WP2FA::get_wp2fa_setting( 'enable_totp' ), true ); ?>
211 >
212 <?php esc_html_e( 'one-time code via Google authenticator app (TOTP)', 'wp-2fa' ); ?>
213 </label>
214 <br/>
215 <label for="email">
216 <input type="checkbox" id="hotp" name="wp_2fa_settings[enable_email]" value="enable_email"
217 <?php checked( WP2FA::get_wp2fa_setting( 'enable_email' ), 'enable_email' ); ?>
218 >
219 <?php esc_html_e( 'one-time code via email (HOTP)', 'wp-2fa' ); ?>
220 </label>
221 <br />
222 </fieldset>
223 </td>
224 </tr>
225 </tbody>
226 </table>
227 <?php
228 }
229
230 /**
231 * Policy settings
232 */
233 private function select_enforcment_policy_setting() {
234 ?>
235 <h3><?php esc_html_e( 'Do you want to enforce 2FA for some, or all the users? ', 'wp-2fa' ); ?></h3>
236 <p class="description">
237 <?php esc_html_e( 'When you enforce 2FA the users will be prompted to configure 2FA the next time they login. Users have a grace period for configuring 2FA. You can configure the grace period and also exclude user(s) or role(s) in this settings page. ', 'wp-2fa' ); ?> <a href="https://www.wpwhitesecurity.com/support/kb/configure-2fa-policies-enforce/?utm_source=plugin&utm_medium=referral&utm_campaign=wp2fa&utm_content=settings+pages" target="_blank"><?php esc_html_e( 'Learn more.', 'wp-2fa' ); ?></a>
238 </p>
239 <table class="form-table">
240 <tbody>
241 <tr>
242 <th><label for="enforcment-policy"><?php esc_html_e( 'Enforce 2FA on:', 'wp-2fa' ); ?></label></th>
243 <td>
244 <fieldset class="contains-hidden-inputs">
245 <label for="all-users">
246 <input type="radio" name="wp_2fa_settings[enforcment-policy]" id="all-users" value="all-users"
247 <?php checked( WP2FA::get_wp2fa_setting( 'enforcment-policy' ), 'all-users' ); ?>
248 >
249 <span><?php esc_html_e( 'All users', 'wp-2fa' ); ?></span>
250 </label>
251
252 <br/>
253 <label for="certain-roles-only">
254 <input type="radio" name="wp_2fa_settings[enforcment-policy]" id="certain-roles-only" value="certain-roles-only"
255 <?php checked( WP2FA::get_wp2fa_setting( 'enforcment-policy' ), 'certain-roles-only' ); ?>
256 <?php checked( WP2FA::get_wp2fa_setting( 'enforcment-policy' ), 'certain-users-only' ); ?>
257 data-unhide-when-checked=".certain-roles-only-inputs, .certain-users-only-inputs">
258 <span><?php esc_html_e( 'Only for specific users and roles', 'wp-2fa' ); ?></span>
259 </label>
260 <fieldset class="hidden certain-roles-only-inputs">
261 <br/>
262 <input type="text" id="enforced_roles_search" placeholder="Search roles">
263 <input type="hidden" id="enforced_roles" name="wp_2fa_settings[enforced_roles]" value="<?php echo esc_attr( WP2FA::get_wp2fa_setting( 'enforced_roles' ) ); ?>">
264 <div id="enforced_roles_buttons"></div>
265 </fieldset>
266 <fieldset class="hidden certain-users-only-inputs">
267 <br/>
268 <input type="text" id="enforced_users_search" placeholder="Search users">
269 <input type="hidden" id="enforced_users" name="wp_2fa_settings[enforced_users]" value="<?php echo esc_attr( WP2FA::get_wp2fa_setting( 'enforced_users' ) ); ?>">
270 <div id="enforced_users_buttons"></div>
271 </fieldset>
272
273 <br/>
274 <label for="do-not-enforce">
275 <input type="radio" name="wp_2fa_settings[enforcment-policy]" id="do-not-enforce" value="do-not-enforce"
276 <?php checked( WP2FA::get_wp2fa_setting( 'enforcment-policy' ), 'do-not-enforce' ); ?>
277 >
278 <span><?php esc_html_e( 'Do not enforce on any users', 'wp-2fa' ); ?></span>
279 </label>
280 <br/>
281 </fieldset>
282 </td>
283 </tr>
284 </tbody>
285 </table>
286 <?php
287 }
288
289 /**
290 * User profile settings
291 */
292 private function user_profile_settings() {
293 ?>
294 <h3><?php esc_html_e( 'Can users access the WordPress dashboard or you have custom profile pages? ', 'wp-2fa' ); ?></h3>
295 <p class="description">
296 <?php esc_html_e( 'If your users do not have access to the WordPress dashboard (because you use custom user profile pages) enable this option. Once enabled, the plugin creates a page which ONLY authenticated users can access to configure their user 2FA settings. A link to this page is sent in the 2FA welcome email.', 'wp-2fa' ); ?></a>
297 </p>
298 <table class="form-table">
299 <tbody>
300 <tr>
301 <th><label for="enforcment-policy"><?php esc_html_e( 'Create custom 2FA settings page', 'wp-2fa' ); ?></label></th>
302 <td>
303 <fieldset>
304 <label class="radio-inline">
305 <input id="use_custom_page" type="radio" name="wp_2fa_settings[create-custom-user-page]" value="yes"
306 <?php checked( WP2FA::get_wp2fa_setting( 'create-custom-user-page' ), 'yes' ); ?>
307 >
308 <?php esc_html_e( 'Yes', 'wp-2fa' ); ?>
309 </label>
310 <label class="radio-inline">
311 <input id="dont_use_custom_page" type="radio" name="wp_2fa_settings[create-custom-user-page]" value="no"
312 <?php checked( WP2FA::get_wp2fa_setting( 'create-custom-user-page' ), 'no' ); ?>
313 <?php checked( WP2FA::get_wp2fa_setting( 'create-custom-user-page' ), '' ); ?>
314 >
315 <?php esc_html_e( 'No', 'wp-2fa' ); ?>
316 </label>
317 </fieldset>
318 </td>
319 </tr>
320 <tr class="custom-user-page-setting disabled">
321 <th><label for="enforcment-policy"><?php esc_html_e( 'Custom 2FA settings page', 'wp-2fa' ); ?></label></th>
322 <td>
323 <fieldset>
324 <?php
325 if ( ! empty( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) ) {
326 $custom_slug = get_post_field( 'post_name', get_post( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) );
327 } else {
328 $custom_slug = WP2FA::get_wp2fa_setting( 'custom-user-page-url' );
329 }
330 ?>
331 <?php esc_html_e( 'Specify a URL for the Custom 2FA settings page URL:', 'wp-2fa' ); ?> <?php echo trailingslashit( get_site_url() ); ?>
332 <input type="text" id="custom-user-page-url" name="wp_2fa_settings[custom-user-page-url]" value="<?php echo sanitize_text_field( $custom_slug ); ?>">
333 </fieldset>
334 <?php
335 if ( ! empty( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) ) {
336 $edit_post_link = get_edit_post_link( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) );
337 $view_post_link = get_permalink( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) );
338 ?>
339 <br>
340 <a href="<?php echo esc_url( $edit_post_link ); ?>" target="_blank" class="button button-secondary" style="margin-right: 5px;"><?php esc_html_e( 'Edit Page', 'wp-2fa' ); ?></a> <a href="<?php echo esc_url( $view_post_link ); ?>" target="_blank" class="button button-primary"><?php esc_html_e( 'View Page', 'wp-2fa' ); ?></a>
341 <?php
342 }
343 ?>
344 </td>
345 </tr>
346 </tbody>
347 </table>
348 <?php
349 }
350
351 /**
352 * Role and users exclusion settings
353 */
354 private function excluded_roles_or_users_setting() {
355 ?>
356 <br>
357 <h3><?php esc_html_e( 'Do you want to exclude any users or roles from 2FA? ', 'wp-2fa' ); ?></h3>
358 <p class="description">
359 <?php esc_html_e( 'If you are enforcing 2FA on all users but for some reason you would like to exclude individual user(s) or users with a specific role, you can exclude them below', 'wp-2fa' ); ?>
360 </p>
361 <table class="form-table">
362 <tbody>
363 <tr>
364 <th><label for="enforcment-policy"><?php esc_html_e( 'Exclude the following users', 'wp-2fa' ); ?></label></th>
365 <td>
366 <fieldset>
367 <input type="text" id="excluded_users_search" placeholder="Search user name">
368 <input type="hidden" id="excluded_users" name="wp_2fa_settings[excluded_users]"
369 value="<?php echo sanitize_text_field( WP2FA::get_wp2fa_setting( 'excluded_users' ) ); ?>">
370 <div id="excluded_users_buttons"></div>
371 </fieldset>
372 </td>
373 </tr>
374 <tr>
375 <th><label for="enforcment-policy"><?php esc_html_e( 'Exclude the following roles:', 'wp-2fa' ); ?></label></th>
376 <td>
377 <fieldset>
378 <input type="text" id="excluded_roles_search" placeholder="Search roles">
379 <input type="hidden" id="excluded_roles" name="wp_2fa_settings[excluded_roles]"
380 value="<?php echo sanitize_text_field( WP2FA::get_wp2fa_setting( 'excluded_roles' ) ); ?>">
381 <div id="excluded_roles_buttons"></div>
382 </fieldset>
383 </td>
384 </tr>
385 </tbody>
386 </table>
387 <?php
388 }
389
390 /**
391 * Role and users exclusion settings
392 */
393 private function excluded_network_sites() {
394 ?>
395 <br>
396 <h3><?php esc_html_e( 'Do you want to exclude all the users of a site from 2FA? ', 'wp-2fa' ); ?></h3>
397 <p class="description">
398 <?php esc_html_e( 'If you are enforcing 2FA on all users but for some reason you do not want to enforce it on a specific sub site, specify the sub site name below:', 'wp-2fa' ); ?>
399 </p>
400 <table class="form-table">
401 <tbody>
402 <tr>
403 <th><label for="enforcment-policy"><?php esc_html_e( 'Exclude the following sites', 'wp-2fa' ); ?></label></th>
404 <td>
405 <fieldset>
406 <input type="text" id="excluded_sites_search" placeholder="Search sites in your network">
407 <input type="hidden" id="excluded_sites" name="wp_2fa_settings[excluded_sites]"
408 value="<?php echo sanitize_text_field( WP2FA::get_wp2fa_setting( 'excluded_sites' ) ); ?>">
409 <div id="excluded_sites_buttons"></div>
410 </fieldset>
411 </td>
412 </tr>
413 </tbody>
414 </table>
415 <?php
416 }
417
418 /**
419 * Grace period settings
420 */
421 private function grace_period_setting() {
422 $user = wp_get_current_user();
423
424 $grace_period = (int) WP2FA::get_wp2fa_setting( 'grace-period' );
425 $testing = get_option( 'wp_2fa_test_grace' );
426 if ( '1' === $testing ) {
427 $grace_max = 600;
428 } else {
429 $grace_max = 10;
430 }
431 ?>
432 <br>
433 <h3><?php esc_html_e( 'How long should the grace period for your users be?', 'wp-2fa' ); ?></h3>
434 <p class="description">
435 <?php esc_html_e( 'When you enforce 2FA on user(s) they have a grace period to configure 2FA. If they fail to configure it within the configured stipulated time, their account will be locked and have to be unlocked manually. Maximum grace period is 10 days.', 'wp-2fa' ); ?> <a href="https://www.wpwhitesecurity.com/support/kb/configure-grace-period-2fa/?utm_source=plugin&utm_medium=referral&utm_campaign=wp2fa&utm_content=settings+pages" target="_blank"><?php esc_html_e( 'Learn more.', 'wp-2fa' ); ?></a>
436 </p>
437 <table class="form-table">
438 <tbody>
439 <tr>
440 <th><label for="grace-period"><?php esc_html_e( 'Grace period', 'wp-2fa' ); ?></label></th>
441 <td>
442 <fieldset>
443 <input type="number" id="grace-period" name="wp_2fa_settings[grace-period]" value="<?php echo esc_attr( $grace_period ); ?>" min="1" max="<?php echo esc_attr( $grace_max ); ?>">
444 <label class="radio-inline">
445 <input type="radio" name="wp_2fa_settings[grace-period-denominator]" value="hours"
446 <?php checked( WP2FA::get_wp2fa_setting( 'grace-period-denominator' ), 'hours' ); ?>
447 >
448 <?php esc_html_e( 'Hours', 'wp-2fa' ); ?>
449 </label>
450 <label class="radio-inline">
451 <input type="radio" name="wp_2fa_settings[grace-period-denominator]" value="days"
452 <?php checked( WP2FA::get_wp2fa_setting( 'grace-period-denominator' ), 'days' ); ?>
453 >
454 <?php esc_html_e( 'Days', 'wp-2fa' ); ?>
455 </label>
456 <?php
457 $testing = get_option( 'wp_2fa_test_grace' );
458 if ( '1' === $testing ) {
459 ?>
460 <label class="radio-inline">
461 <input type="radio" name="wp_2fa_settings[grace-period-denominator]" value="seconds"
462 <?php checked( WP2FA::get_wp2fa_setting( 'grace-period-denominator' ), 'seconds' ); ?>
463 >
464 <?php esc_html_e( 'Seconds', 'wp-2fa' ); ?>
465 </label>
466 <?php
467 }
468
469 if ( ! empty( WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' ) ) ) {
470 $last_user_to_update_settings = WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' );
471 } else {
472 $last_user_to_update_settings = $user->ID;
473 }
474
475 ?>
476 <input type="hidden" id="2fa_main_user" name="wp_2fa_settings[2fa_settings_last_updated_by]" value="<?php echo esc_attr( $last_user_to_update_settings ); ?>">
477 </fieldset>
478 </td>
479 </tr>
480 </tbody>
481 </table>
482
483 <h3><?php esc_html_e( 'How often should the plugin check if a user\'s grace period is over?', 'wp-2fa' ); ?></h3>
484 <p class="description">
485 <?php esc_html_e( 'By default the plugin checks if a users grace periods to setup 2FA has passed when the user tries to login. If you would like the plugin to advise the user within an hour, enable the below option to add a cron job that runs every hour.', 'wp-2fa' ); ?>
486 </p>
487 <table class="form-table">
488 <tbody>
489 <tr>
490 <th><label for="grace-period"><?php esc_html_e( 'Enable cron', 'wp-2fa' ); ?></label></th>
491 <td>
492 <fieldset>
493 <input type="checkbox" id="grace-cron" name="wp_2fa_settings[enable_grace_cron]" value="enable_grace_cron"
494 <?php checked( 1, WP2FA::get_wp2fa_setting( 'enable_grace_cron' ), true ); ?>
495 >
496 <?php esc_html_e( 'Use cron job to check grace periods', 'wp-2fa' ); ?>
497 </fieldset>
498 </td>
499 </tr>
500 <tr class="disabled destory-session-setting">
501 <th><label for="destory-session"><?php esc_html_e( 'Destroy session', 'wp-2fa' ); ?></label></th>
502 <td>
503 <fieldset>
504 <input type="checkbox" id="destory-session" name="wp_2fa_settings[enable_destroy_session]" value="enable_destroy_session"
505 <?php checked( 1, WP2FA::get_wp2fa_setting( 'enable_destroy_session' ), true ); ?>
506 >
507 <?php esc_html_e( 'Destory user session when grace period expires?', 'wp-2fa' ); ?>
508 </fieldset>
509 </td>
510 </tr>
511 </tbody>
512 </table>
513 <?php
514 }
515
516 /**
517 * Limit settings setting
518 */
519 private function limit_settings_access() {
520 ?>
521 <br>
522 <h3><?php esc_html_e( 'Limit 2FA settings access?', 'wp-2fa' ); ?></h3>
523 <p class="description">
524 <?php esc_html_e( 'Use this setting to hide this plugin configuration area from all other admins.', 'wp-2fa' ); ?>
525 </p>
526 <table class="form-table">
527 <tbody>
528 <tr>
529 <th><label for="grace-period"><?php esc_html_e( 'Limited access', 'wp-2fa' ); ?></label></th>
530 <td>
531 <fieldset>
532 <input type="checkbox" id="limit_access" name="wp_2fa_settings[limit_access]" value="limit_access"
533 <?php checked( 1, WP2FA::get_wp2fa_setting( 'limit_access' ), true ); ?>
534 >
535 <?php esc_html_e( 'Hide settings from other administrators', 'wp-2fa' ); ?>
536 </fieldset>
537 </td>
538 </tr>
539 </tbody>
540 </table>
541 <?php
542 }
543
544 /**
545 * Limit settings setting
546 */
547 private function remove_data_upon_uninstall() {
548 ?>
549 <div class="danger-zone-wrapper">
550 <h3><?php esc_html_e( 'Do you want to delete the plugin data from the database upon uninstall?', 'wp-2fa' ); ?></h3>
551 <p class="description">
552 <?php esc_html_e( 'The plugin saves its settings in the WordPress database. By default the plugin settings are kept in the database so if it is installed again, you do not have to reconfigure the plugin. Enable this setting to delete the plugin settings from the database upon uninstall.', 'wp-2fa' ); ?>
553 </p>
554 <table class="form-table">
555 <tbody>
556 <tr>
557 <th><label for="delete_data"><?php esc_html_e( 'Delete data', 'wp-2fa' ); ?></label></th>
558 <td>
559 <fieldset>
560 <input type="checkbox" id="elete_data" name="wp_2fa_settings[delete_data_upon_uninstall]" value="delete_data_upon_uninstall"
561 <?php checked( 1, WP2FA::get_wp2fa_setting( 'delete_data_upon_uninstall' ), true ); ?>
562 >
563 <?php esc_html_e( 'Delete data upon uninstall', 'wp-2fa' ); ?>
564 </fieldset>
565 </td>
566 </tr>
567 </tbody>
568 </table>
569 </div>
570 <?php
571 }
572
573 /**
574 * Get all useers
575 */
576 public function get_all_users() {
577 // Die if user does not have permission to view.
578 if ( ! current_user_can( 'administrator' ) ) {
579 die( 'Access Denied.' );
580 }
581 // Filter $_GET array for security.
582 $get_array = filter_input_array( INPUT_GET );
583
584 // Die if nonce verification failed.
585 if ( ! wp_verify_nonce( sanitize_text_field( $get_array['wp_2fa_nonce'] ), 'wp-2fa-settings-nonce' ) ) {
586 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
587 }
588 // Fetch users.
589 $users = array();
590 if ( WP2FA::is_this_multisite() ) {
591 $users_args = array( 'blog_id' => 0 );
592 } else {
593 $users_args = array();
594 }
595
596 foreach ( get_users( $users_args ) as $user ) {
597 if ( strpos( $user->user_login, $get_array['term'] ) !== false ) {
598 array_push( $users, $user->user_login );
599 }
600 }
601 echo wp_json_encode( $users );
602 exit;
603 }
604
605 /**
606 * Get all network sites
607 */
608 public function get_all_network_sites() {
609 // Die if user does not have permission to view.
610 if ( ! current_user_can( 'administrator' ) ) {
611 die( 'Access Denied.' );
612 }
613 // Filter $_GET array for security.
614 $get_array = filter_input_array( INPUT_GET );
615 // Die if nonce verification failed.
616 if ( ! wp_verify_nonce( sanitize_text_field( $get_array['wp_2fa_nonce'] ), 'wp-2fa-settings-nonce' ) ) {
617 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
618 }
619 // Fetch sites.
620 $sites_found = array();
621
622 foreach ( get_sites() as $site ) {
623 $subsite_id = get_object_vars( $site )['blog_id'];
624 $subsite_name = get_blog_details( $subsite_id )->blogname;
625 $site_details = '';
626 $site_details[$subsite_id] = $subsite_name;
627 if ( stripos( $subsite_name, $get_array['term'] ) !== false ) {
628 $site_details = $subsite_name . ':' . $subsite_id;
629 array_push( $sites_found, $site_details );
630 }
631 }
632 echo wp_json_encode( $sites_found );
633 exit;
634 }
635
636 /**
637 * Unlock users accounts if they have overrun grace period
638 *
639 * @param int $user_id User ID.
640 */
641 public function unlock_account( $user_id ) {
642 // Die if user does not have permission to view.
643 if ( ! current_user_can( 'administrator' ) ) {
644 die( 'Access Denied.' );
645 }
646
647 $grace_period = WP2FA::get_wp2fa_setting( 'grace-period' );
648 $grace_period_denominator = WP2FA::get_wp2fa_setting( 'grace-period-denominator' );
649 $create_a_string = $grace_period . ' ' . $grace_period_denominator;
650 // Turn that string into a time.
651 $grace_expiry = strtotime( $create_a_string );
652
653 // Filter $_GET array for security.
654 $get_array = filter_input_array( INPUT_GET );
655 $nonce = sanitize_text_field( $get_array['wp_2fa_nonce'] );
656
657 // Die if nonce verification failed.
658 if ( ! wp_verify_nonce( $nonce, 'wp-2fa-unlock-account-nonce' ) ) {
659 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
660 }
661
662 if ( isset( $get_array['user_id'] ) ) {
663 $unlock = delete_user_meta( intval( $get_array['user_id'] ), 'wp_2fa_user_grace_period_expired' );
664 $notification = delete_user_meta( intval( $get_array['user_id'] ), 'wp_2fa_locked_account_notification' );
665 $update = update_user_meta( intval( $get_array['user_id'] ), 'wp_2fa_grace_period_expiry', $grace_expiry );
666 $this->send_account_unlocked_email( intval( $get_array['user_id'] ) );
667 add_action( 'admin_notices', array( $this, 'user_unlocked_notice' ) );
668 }
669 }
670
671 /**
672 * Remove user 2fa config
673 *
674 * @param int $user_id User ID.
675 */
676 public function remove_user_2fa( $user_id ) {
677 // Filter $_GET array for security.
678 $get_array = filter_input_array( INPUT_GET );
679 $nonce = sanitize_text_field( $get_array['wp_2fa_nonce'] );
680
681 if ( ! wp_verify_nonce( $nonce, 'wp-2fa-remove-user-2fa-nonce' ) ) {
682 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
683 }
684
685 if ( isset( $get_array['user_id'] ) ) {
686 $user_id = intval( $get_array['user_id'] );
687 $wipe_totp_key = delete_user_meta( $user_id, 'wp_2fa_totp_key' );
688 $wipe_backup_codes = delete_user_meta( $user_id, 'wp_2fa_backup_codes' );
689 $wipe_enabled_methods = delete_user_meta( $user_id, 'wp_2fa_enabled_methods' );
690 $wipe_grace_period = delete_user_meta( $user_id, 'wp_2fa_grace_period_expiry' );
691 $wipe_email_address = delete_user_meta( $user_id, 'wp_2fa_nominated_email_address' );
692 $is_needed = Authentication::is_user_eligible_for_2fa( $user_id );
693 if ( $is_needed ) {
694 if ( 'do-not-enforce' !== WP2FA::get_wp2fa_setting( 'enforcment-policy' ) ) {
695 // Turn inputs into a useable string.
696 $create_a_string = WP2FA::get_wp2fa_setting( 'grace-period' ) . ' ' . WP2FA::get_wp2fa_setting( 'grace-period-denominator' );
697 // Turn that string into a time.
698 $grace_expiry = strtotime( $create_a_string );
699 update_user_meta( $user_id, 'wp_2fa_grace_period_expiry', $grace_expiry );
700 update_user_meta( $user_id, 'wp_2fa_update_nag_dismissed', true );
701 }
702 }
703 if ( isset( $get_array['admin_reset'] ) ) {
704 add_action( 'admin_notices', array( $this, 'admin_deleted_2fa_notice' ) );
705 } else {
706 add_action( 'admin_notices', array( $this, 'user_deleted_2fa_notice' ) );
707 }
708 }
709 }
710
711 /**
712 * Send account unlocked notification via email.
713 *
714 * @param int $user_id user ID.
715 */
716 public static function send_account_unlocked_email( $user_id ) {
717 // Bail if the user has not enabled this email.
718 if ( 'enable_account_unlocked_email' !== WP2FA::get_wp2fa_email_templates( 'send_account_unlocked_email' ) ) {
719 return false;
720 }
721
722 // Grab user data.
723 $user = get_userdata( $user_id );
724 // Grab user email.
725 $email = $user->user_email;
726 // Setup the email contents.
727 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_account_unlocked_email_subject' ) ) );
728 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_account_unlocked_email_body' ), $user_id ) );
729 // Specify our desired headers.
730 $headers = 'Content-type: text/html;charset=utf-8' . "\r\n";
731
732 if ( 'use-custom-email' === WP2FA::get_wp2fa_email_templates( 'email_from_setting' ) ) {
733 $headers .= "From: ". WP2FA::get_wp2fa_email_templates( 'custom_from_display_name' ) ." <". WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' ) .">" . "\r\n";
734 }
735
736 // Fire our email.
737 $mail = wp_mail( $user->user_email, $subject, $message, $headers );
738 }
739
740 /**
741 * Validate options before saving
742 *
743 * @param array $input The settings array.
744 */
745 public function validate_and_sanitize( $input ) {
746 // Bail if user doesnt have permissions to be here.
747 if ( ! current_user_can( 'manage_options' ) ) {
748 return;
749 }
750
751 // Setup args we may need, depending if this is a MS setup or not.
752 $users = array();
753 if ( WP2FA::is_this_multisite() ) {
754 $users_args = array( 'blog_id' => 0 );
755 } else {
756 $users_args = array();
757 }
758
759 $users = get_users( $users_args );
760
761 if ( ! isset( $input['enable_totp'] ) && ! isset( $input['enable_email'] ) ) {
762 add_settings_error(
763 'wp_2fa_settings',
764 esc_attr( 'enable_email_settings_error' ),
765 esc_html__( 'At least one 2FA method should be enabled.', 'wp-2fa' ),
766 'error'
767 );
768 }
769
770 // Compare current to old value to see if a method which was once enabled, has now been disabled.
771 if ( ! isset( $input['enable_totp'] ) && 'enable_totp' === WP2FA::get_wp2fa_setting( 'enable_totp' ) ) {
772 foreach ( $users as $user ) {
773 $enabled = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
774 if ( 'totp' === $enabled ) {
775 delete_user_meta( $user->ID, 'wp_2fa_enabled_methods', 'totp' );
776 update_user_meta( $user->ID, 'wp_2fa_user_needs_to_reconfigure_2fa', true );
777 }
778 }
779 }
780 if ( ! isset( $input['enable_email'] ) && 'enable_email' === WP2FA::get_wp2fa_setting( 'enable_email' ) ) {
781 foreach ( $users as $user ) {
782 $enabled = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
783 if ( 'email' === $enabled ) {
784 delete_user_meta( $user->ID, 'wp_2fa_enabled_methods', 'email' );
785 update_user_meta( $user->ID, 'wp_2fa_user_needs_to_reconfigure_2fa', true );
786 }
787 }
788 }
789
790 if ( isset( $input['enable_totp'] ) && 'enable_totp' === $input['enable_totp'] ) {
791 $output['enable_totp'] = sanitize_text_field( $input['enable_totp'] );
792 }
793
794 if ( isset( $input['enable_email'] ) && 'enable_email' === $input['enable_email'] ) {
795 $output['enable_email'] = sanitize_text_field( $input['enable_email'] );
796 }
797
798 if ( isset( $input['enforcment-policy'] ) && 'all-users' === $input['enforcment-policy'] || isset( $input['enforcment-policy'] ) && 'certain-users-only' === $input['enforcment-policy'] || isset( $input['enforcment-policy'] ) && 'certain-roles-only' === $input['enforcment-policy'] || isset( $input['enforcment-policy'] ) && 'do-not-enforce' === $input['enforcment-policy'] ) {
799 // Clear enforced roles/users if setting has changed.
800 if ( 'all-users' === $input['enforcment-policy'] ) {
801 $input['enforced_users'] = '';
802 $input['enforced_roles'] = '';
803 }
804
805 $output['enforcment-policy'] = sanitize_text_field( $input['enforcment-policy'] );
806 }
807
808 if ( WP2FA::get_wp2fa_setting( 'enforcment-policy' ) !== $input['enforcment-policy'] && 'do-not-enforce' === $input['enforcment-policy'] ) {
809 $input['enforced_users'] = '';
810 $input['enforced_roles'] = '';
811 }
812
813 if ( 'certain-roles-only' === $input['enforcment-policy'] && empty( $input['enforced_roles'] ) && empty( $input['enforced_users'] ) ) {
814 add_settings_error(
815 'wp_2fa_settings',
816 esc_attr( 'enforced_roles_settings_error' ),
817 esc_html__( 'You must specify at least one role or user', 'wp-2fa' ),
818 'error'
819 );
820 }
821
822 if ( isset( $input['enforced_roles'] ) ) {
823 $output['enforced_roles'] = trim( sanitize_text_field( $input['enforced_roles'] ) );
824 }
825
826 if ( isset( $input['enforced_users'] ) ) {
827 $output['enforced_users'] = trim( sanitize_text_field( $input['enforced_users'] ) );
828 }
829
830 if ( isset( $input['excluded_users'] ) ) {
831 $output['excluded_users'] = trim( sanitize_text_field( $input['excluded_users'] ) );
832
833 // Wipe user 2fa data.
834 $user_array = explode( ',', $output['excluded_users'] );
835 foreach ( $user_array as $user ) {
836 if ( ! empty( $user ) ) {
837 $user_to_wipe = get_user_by( 'login', $user );
838 $wipe_totp_key = delete_user_meta( $user_to_wipe->ID, 'wp_2fa_totp_key' );
839 $wipe_backup_codes = delete_user_meta( $user_to_wipe->ID, 'wp_2fa_backup_codes' );
840 $wipe_enabled_methods = delete_user_meta( $user_to_wipe->ID, 'wp_2fa_enabled_methods' );
841 $wipe_grace_period = delete_user_meta( $user_to_wipe->ID, 'wp_2fa_grace_period_expiry' );
842 }
843 }
844 }
845
846 if ( isset( $input['excluded_roles'] ) ) {
847 $output['excluded_roles'] = trim( sanitize_text_field( $input['excluded_roles'] ) );
848
849 // Wipe user 2fa data.
850 $excluded_roles_array = array_filter( explode( ',', strtolower( $output['excluded_roles'] ) ) );
851 foreach ( $users as $user ) {
852 // Compare the user roles to the ones we are excluding and see if we get a match.
853 $result = array_intersect( $excluded_roles_array, $user->roles );
854 // If we do, lets wipe!
855 if ( ! empty( $result ) ) {
856 $wipe_totp_key = delete_user_meta( $user->ID, 'wp_2fa_totp_key' );
857 $wipe_backup_codes = delete_user_meta( $user->ID, 'wp_2fa_backup_codes' );
858 $wipe_enabled_methods = delete_user_meta( $user->ID, 'wp_2fa_enabled_methods' );
859 $wipe_grace_period = delete_user_meta( $user->ID, 'wp_2fa_grace_period_expiry' );
860 }
861 }
862 }
863
864 if ( WP2FA::is_this_multisite() ) {
865 if ( isset( $input['excluded_sites'] ) ) {
866 $output['excluded_sites'] = trim( sanitize_text_field( $input['excluded_sites'] ) );
867 }
868 } else {
869 $output['excluded_sites'] = '';
870 }
871
872 if ( isset( $input['grace-period'] ) ) {
873 if ( 0 === (int) $input['grace-period'] ) {
874 add_settings_error(
875 'wp_2fa_settings',
876 esc_attr( 'grace_settings_error' ),
877 esc_html__( 'Grace period must be at least 1 day/hour', 'wp-2fa' ),
878 'error'
879 );
880 $output['grace-period'] = 1;
881 } else {
882 $output['grace-period'] = (int) $input['grace-period'];
883 }
884 }
885
886 if ( isset( $input['grace-period-denominator'] ) && 'days' === $input['grace-period-denominator'] || isset( $input['grace-period-denominator'] ) && 'hours' === $input['grace-period-denominator'] || isset( $input['grace-period-denominator'] ) && 'seconds' === $input['grace-period-denominator'] ) {
887 $output['grace-period-denominator'] = sanitize_text_field( $input['grace-period-denominator'] );
888 }
889
890 if ( isset( $input['create-custom-user-page'] ) && 'yes' === $input['create-custom-user-page'] || isset( $input['create-custom-user-page'] ) && 'no' === $input['create-custom-user-page'] ) {
891 $output['create-custom-user-page'] = sanitize_text_field( $input['create-custom-user-page'] );
892 }
893
894 if ( isset( $input['custom-user-page-url'] ) ) {
895 if ( $input['custom-user-page-url'] !== WP2FA::get_wp2fa_setting( 'custom-user-page-url' ) ) {
896 if ( ! empty( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) ) {
897 $updated_post = array(
898 'ID' => WP2FA::get_wp2fa_setting( 'custom-user-page-id' ),
899 'post_name' => sanitize_title_with_dashes( $input['custom-user-page-url'] ),
900 );
901 wp_update_post( $updated_post );
902 $output['custom-user-page-url'] = sanitize_title_with_dashes( $input['custom-user-page-url'] );
903 $output['custom-user-page-id'] = WP2FA::get_wp2fa_setting( 'custom-user-page-id' );
904 } elseif( 'yes' === $input['create-custom-user-page'] && ! empty( $input['custom-user-page-url'] ) ) {
905 $output['custom-user-page-url'] = sanitize_title_with_dashes( $input['custom-user-page-url'] );
906 $create_page = $this->generate_custom_user_profile_page( $output['custom-user-page-url'] );
907 $output['custom-user-page-id'] = (int) $create_page;
908 $email_options = get_option( 'wp_2fa_email_settings' );
909 if ( ! empty( $email_options ) ) {
910 unset( $email_options[ 'enforced_email_body' ] );
911 unset( $email_options[ 'user_account_unlocked_email_body' ] );
912 }
913 if ( WP2FA::is_this_multisite() ) {
914 update_network_option( null, 'wp_2fa_email_settings', $email_options );
915 } else {
916 update_option( 'wp_2fa_email_settings', $email_options );
917 }
918 }
919
920 } else {
921 $output['custom-user-page-url'] = sanitize_title_with_dashes( $input['custom-user-page-url'] );
922 $output['custom-user-page-id'] = WP2FA::get_wp2fa_setting( 'custom-user-page-id' );
923 }
924 }
925
926 if ( isset( $_REQUEST['page'] ) && 'wp-2fa-setup' !== $_REQUEST['page'] || isset( $_REQUEST['wp_2fa_settings']['create-custom-user-page'] ) ) {
927
928 if ( isset( $input['create-custom-user-page'] ) && 'no' === $input['create-custom-user-page'] ) {
929 $output['custom-user-page-url'] = '';
930 $output['custom-user-page-id'] = '';
931 wp_delete_post( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ), true );
932 $email_options = get_option( 'wp_2fa_email_settings' );
933 if ( ! empty( $email_options ) ) {
934 unset( $email_options[ 'enforced_email_body' ] );
935 unset( $email_options[ 'user_account_unlocked_email_body' ] );
936 }
937 if ( WP2FA::is_this_multisite() ) {
938 update_network_option( null, 'wp_2fa_email_settings', $email_options );
939 } else {
940 update_option( 'wp_2fa_email_settings', $email_options );
941 }
942 }
943
944 }
945
946 if ( isset( $input['create-custom-user-page'] ) && 'yes' === $input['create-custom-user-page'] && empty( $input['custom-user-page-url'] ) ) {
947 add_settings_error(
948 'wp_2fa_settings',
949 esc_attr( 'no_page_slug_provided' ),
950 esc_html__( 'You must provide a new page slug.', 'wp-2fa' ),
951 'error'
952 );
953 }
954
955 if ( isset( $input['enable_grace_cron'] ) ) {
956 $output['enable_grace_cron'] = (bool) $input['enable_grace_cron'];
957 }
958
959 if ( isset( $input['enable_destroy_session'] ) ) {
960 $output['enable_destroy_session'] = (bool) $input['enable_destroy_session'];
961 }
962
963 if ( isset( $input['2fa_settings_last_updated_by'] ) ) {
964 $output['2fa_settings_last_updated_by'] = esc_attr( trim( $input['2fa_settings_last_updated_by'] ) );
965 }
966
967 if ( isset( $input['limit_access'] ) ) {
968 $output['limit_access'] = (bool) $input['limit_access'];
969 }
970
971 if ( isset( $input['delete_data_upon_uninstall'] ) ) {
972 $output['delete_data_upon_uninstall'] = (bool) $input['delete_data_upon_uninstall'];
973 }
974
975 if ( isset( $input['grace-period'] ) && isset( $input['grace-period-denominator'] ) ) {
976 // Turn inputs into a useable string.
977 $create_a_string = $output['grace-period'] . ' ' . $output['grace-period-denominator'];
978 // Turn that string into a time.
979 $grace_expiry = strtotime( $create_a_string );
980 $output['grace-period-expiry-time'] = sanitize_text_field( $grace_expiry );
981 }
982
983 // Fetch users and apply the grace period tp their user meta.
984 if ( isset( $input['enforcment-policy'] ) && 'do-not-enforce' !== $input['enforcment-policy'] && ! isset( $input['grace-period-expiry-time'] ) ) {
985 // Flush the old expiry away from ALL users, we will re-apply them based on the current setup at the end of this.
986 foreach ( $users as $user ) {
987 delete_user_meta( $user->ID, 'wp_2fa_grace_period_expiry' );
988 }
989 // If we are specifying to enforce 2fa for specific users, we have no need to check if they are eligble or excluded, so we dont.
990 if ( isset( $input['enforcment-policy'] ) && 'certain-roles-only' === $input['enforcment-policy'] && isset( $input['enforced_users'] ) && WP2FA::get_wp2fa_setting( 'enforced_users' ) !== $input['enforced_users'] || isset( $input['enforcment-policy'] ) && 'certain-roles-only' === $input['enforcment-policy'] && isset( $input['enforced_roles'] ) && WP2FA::get_wp2fa_setting( 'enforced_roles' ) !== $input['enforced_roles'] ) {
991 $enforced_users_array = array_filter( explode( ',', $input['enforced_users'] ) );
992 foreach ( $users as $user ) {
993 if ( in_array( $user->user_login, $enforced_users_array ) ) {
994 update_user_meta( $user->ID, 'wp_2fa_grace_period_expiry', $grace_expiry );
995 self::send_2fa_enforced_email( $user->ID );
996 } else {
997 if ( isset( $output['enforced_roles'] ) && empty( $output['enforced_roles'] ) ) {
998 $enforced_roles = 'none';
999 } else {
1000 $enforced_roles = $output['enforced_roles'];
1001 }
1002 if ( isset( $output['enforced_users'] ) && empty( $output['enforced_users'] ) ) {
1003 $enforced_users = 'none';
1004 } else {
1005 $enforced_users = $output['enforced_users'];
1006 }
1007 $is_needed = Authentication::is_user_eligible_for_2fa( $user->ID, $input['enforcment-policy'], $output['excluded_users'], $output['excluded_roles'], $enforced_users, $enforced_roles );
1008 $is_user_excluded = WP2FA::is_user_excluded( $user, $output['excluded_users'], $output['excluded_roles'], $output['excluded_sites'] );
1009 if ( $is_needed && ! $is_user_excluded ) {
1010 update_user_meta( $user->ID, 'wp_2fa_grace_period_expiry', $grace_expiry );
1011 self::send_2fa_enforced_email( $user->ID );
1012 }
1013 }
1014 }
1015
1016 } else {
1017 foreach ( $users as $user ) {
1018 $is_needed = Authentication::is_user_eligible_for_2fa( $user->ID, $input['enforcment-policy'], $output['excluded_users'], $output['excluded_roles'], $output['enforced_users'], $output['enforced_roles'] );
1019 $is_user_excluded = WP2FA::is_user_excluded( $user, $output['excluded_users'], $output['excluded_roles'], $output['excluded_sites'] );
1020 if ( $is_needed && ! $is_user_excluded ) {
1021 update_user_meta( $user->ID, 'wp_2fa_grace_period_expiry', $grace_expiry );
1022 self::send_2fa_enforced_email( $user->ID );
1023 }
1024 }
1025 }
1026
1027 }
1028
1029 if ( isset( $input['enforcment-policy'] ) && 'do-not-enforce' === $input['enforcment-policy'] && ! isset( $input['grace-period-expiry-time'] ) ) {
1030 // Flush the old expiry away from ALL users, we will re-apply them based on the current setup at the end of this.
1031 foreach ( $users as $user ) {
1032 delete_user_meta( $user->ID, 'wp_2fa_grace_period_expiry' );
1033 }
1034 }
1035
1036 // Remove duplicates from settings errors. We do this as this sanitization callback is actually fired twice, so we end up with duplicates when saving the settings for the FIRST TIME only. The issue is not present once the settings are in the DB as the sanitization wont fire again. For details on this core issue - https://core.trac.wordpress.org/ticket/21989
1037 global $wp_settings_errors;
1038 if ( isset( $wp_settings_errors ) ) {
1039 $errors = array_map( "unserialize", array_unique( array_map( "serialize", $wp_settings_errors ) ) );
1040 $wp_settings_errors = $errors;
1041 }
1042
1043 return $output;
1044 }
1045
1046 /**
1047 * Hide settings menu item
1048 */
1049 public function hide_settings() {
1050 $user = wp_get_current_user();
1051
1052 // Check we have a user before doing anything else.
1053 if ( is_a( $user, '\WP_User' ) ) {
1054 $user_id = (int) $user->ID;
1055 if ( ! empty( WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' ) ) ) {
1056 $main_user = (int) WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' );
1057 } else {
1058 $main_user = '';
1059 }
1060 if ( ! empty( WP2FA::get_wp2fa_setting( 'limit_access' ) ) && $user->ID !== $main_user ) {
1061 // Remove admin menu item.
1062 remove_submenu_page( 'options-general.php', 'wp-2fa-settings' );
1063 }
1064 }
1065 }
1066
1067 /**
1068 * Add unlock user link to user actions.
1069 *
1070 * @param array $links Default row content.
1071 */
1072 public function add_plugin_action_links( $links ) {
1073
1074 if ( WP2FA::is_this_multisite() ) {
1075 $url = network_admin_url( '/settings.php?page=wp-2fa-settings' );
1076 } else {
1077 $url = admin_url( '/options-general.php?page=wp-2fa-settings' );
1078 }
1079
1080 $links = array_merge(
1081 array(
1082 '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Configure 2FA Settings', 'wp-2fa' ) . '</a>',
1083 ),
1084 $links
1085 );
1086
1087 return $links;
1088
1089 }
1090
1091 /**
1092 * User unlocked notice.
1093 */
1094 public function user_unlocked_notice() {
1095 ?>
1096 <div class="notice notice-success is-dismissible">
1097 <p><?php esc_html_e( 'User account successfully unlocked. User can login again.', 'wp-2fa' ); ?></p>
1098 <button type="button" class="notice-dismiss">
1099 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
1100 </button>
1101 </div>
1102 <?php
1103 }
1104
1105 /**
1106 * User deleted 2FA settings notification
1107 */
1108 public function user_deleted_2fa_notice() {
1109 ?>
1110 <div class="notice notice-success is-dismissible">
1111 <p><?php esc_html_e( 'Your 2FA settings have been removed.', 'wp-2fa' ); ?></p>
1112 <button type="button" class="notice-dismiss">
1113 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
1114 </button>
1115 </div>
1116 <?php
1117 }
1118
1119 /**
1120 * Admin deleted user 2FA settings notification
1121 */
1122 public function admin_deleted_2fa_notice() {
1123 ?>
1124 <div class="notice notice-success is-dismissible">
1125 <p><?php esc_html_e( 'User 2FA settings have been removed.', 'wp-2fa' ); ?></p>
1126 <button type="button" class="notice-dismiss">
1127 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
1128 </button>
1129 </div>
1130 <?php
1131 }
1132
1133 /**
1134 * Semd email to let user know they need to enabled 2FA
1135 *
1136 * @param int $user_id User ID.
1137 */
1138 public static function send_2fa_enforced_email( $user_id ) {
1139 // Bail if the user has not enabled this email.
1140 if ( 'enable_enforced_email' !== WP2FA::get_wp2fa_email_templates( 'send_enforced_email' ) ) {
1141 return false;
1142 }
1143
1144 $user_id = (int) $user_id;
1145 // Grab user data.
1146 $user = get_userdata( $user_id );
1147
1148 // Check if user has any enabled 2FA methods before sending.
1149 $enabled_methods = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
1150 if ( ! empty( $enabled_methods ) ) {
1151 return false;
1152 }
1153
1154 // Grab user email.
1155 $email = $user->user_email;
1156
1157 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'enforced_email_subject' ), $user_id ) );
1158 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'enforced_email_body' ), $user_id ) );
1159
1160 $headers = 'Content-type: text/html;charset=utf-8' . "\r\n";
1161
1162 if ( 'use-custom-email' === WP2FA::get_wp2fa_email_templates( 'email_from_setting' ) ) {
1163 $headers .= "From: ". WP2FA::get_wp2fa_email_templates( 'custom_from_display_name' ) ." <". WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' ) .">" . "\r\n";
1164 }
1165
1166 $mail = wp_mail( $user->user_email, $subject, $message, $headers );
1167 }
1168
1169 public function update_wp2fa_network_options() {
1170 check_admin_referer( 'wp_2fa_settings-options' );
1171
1172 if ( isset( $_POST['wp_2fa_settings'] ) ) {
1173 $options = $this->validate_and_sanitize( wp_unslash( $_POST['wp_2fa_settings'] ) );
1174 $update_options = update_network_option( null, 'wp_2fa_settings', $options );
1175 }
1176
1177 // redirect back to our options page.
1178 wp_safe_redirect(
1179 add_query_arg(
1180 array(
1181 'page' => 'wp-2fa-settings',
1182 'wp_2fa_network_settings_updated' => 'true',
1183 ),
1184 network_admin_url( 'settings.php' )
1185 )
1186 );
1187 exit;
1188 }
1189
1190 /**
1191 * Handle saving email options to the network main site options.
1192 */
1193 public function update_wp2fa_network_email_options() {
1194 if ( isset( $_POST['email_from_setting'] ) ) {
1195 $options = $this->validate_and_sanitize_email( wp_unslash( $_POST ) );
1196
1197 if ( isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_display_name'] ) && empty( $_POST['custom_from_display_name'] ) || isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_email_address'] ) && empty( $_POST['custom_from_email_address'] ) ) {
1198 // redirect back to our options page.
1199 wp_safe_redirect(
1200 add_query_arg(
1201 array(
1202 'page' => 'wp-2fa-settings',
1203 'wp_2fa_network_settings_updated' => 'false',
1204 'tab' => 'email-settings'
1205 ),
1206 network_admin_url( 'settings.php' )
1207 )
1208 );
1209 exit;
1210 }
1211
1212 $update_options = update_network_option( null, 'wp_2fa_email_settings', $options );
1213 }
1214
1215 // redirect back to our options page.
1216 wp_safe_redirect(
1217 add_query_arg(
1218 array(
1219 'page' => 'wp-2fa-settings',
1220 'wp_2fa_network_settings_updated' => 'true',
1221 'tab' => 'email-settings'
1222 ),
1223 network_admin_url( 'settings.php' )
1224 )
1225 );
1226 exit;
1227 }
1228
1229 /**
1230 * These are used instead of add_settings_error which in a network site. Used to show if settings have been updated or failed.
1231 */
1232 public function settings_saved_network_admin_notice() {
1233 if ( isset( $_GET['wp_2fa_network_settings_updated'] ) && $_GET['wp_2fa_network_settings_updated'] == 'true' ): ?>
1234 <div class="notice notice-success is-dismissible">
1235 <p><?php esc_html_e( '2FA Settings Updated', 'wp-2fa' ); ?></p>
1236 <button type="button" class="notice-dismiss">
1237 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
1238 </button>
1239 </div>
1240 <?php
1241 endif;
1242 if ( isset( $_GET['wp_2fa_network_settings_updated'] ) && $_GET['wp_2fa_network_settings_updated'] == 'false' ): ?>
1243 <div class="notice notice-error is-dismissible">
1244 <p><?php esc_html_e( 'Please ensure both custom email address and display name are provided.', 'wp-2fa' ); ?></p>
1245 <button type="button" class="notice-dismiss">
1246 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
1247 </button>
1248 </div>
1249 <?php
1250 endif;
1251 }
1252
1253 /**
1254 * Email settings
1255 */
1256 private function email_from_settings() {
1257 ?>
1258 <h3><?php esc_html_e( 'Which email address should the plugin use as a from address?', 'wp-2fa' ); ?></h3>
1259 <p class="description">
1260 <?php esc_html_e( 'Use these settings to customize the "from" name and email address for all correspondence sent from our plugin.', 'wp-2fa' ); ?>
1261 </p>
1262 <table class="form-table">
1263 <tbody>
1264 <tr>
1265 <th><label for="2fa-method"><?php esc_html_e( 'From email & name', 'wp-2fa' ); ?></label>
1266 </th>
1267 <td>
1268 <fieldset class="contains-hidden-inputs">
1269 <label for="use-defaults">
1270 <input type="radio" name="email_from_setting" id="use-defaults" value="use-defaults"
1271 <?php checked( WP2FA::get_wp2fa_email_templates( 'email_from_setting' ), 'use-defaults' ); ?>
1272 >
1273 <span><?php esc_html_e( 'Use the email address from the WordPress general settings.', 'wp-2fa' ); ?></span>
1274 </label>
1275
1276 <br/>
1277 <label for="use-custom-email">
1278 <input type="radio" name="email_from_setting" id="use-custom-email" value="use-custom-email"
1279 <?php checked( WP2FA::get_wp2fa_email_templates( 'email_from_setting' ), 'use-custom-email' ); ?>
1280 data-unhide-when-checked=".custom-from-inputs">
1281 <span><?php esc_html_e( 'Use another email address', 'wp-2fa' ); ?></span>
1282 </label>
1283 <fieldset class="hidden custom-from-inputs">
1284 <br/>
1285 <span><?php esc_html_e( 'Email Address:', 'wp-2fa' ); ?></span> <input type="text" id="custom_from_email_address" name="custom_from_email_address" value="<?php echo WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' ); ?>"><br><br>
1286 <span><?php esc_html_e( 'Display Name:', 'wp-2fa' ); ?></span> <input type="text" id="custom_from_display_name" name="custom_from_display_name" value="<?php echo WP2FA::get_wp2fa_email_templates( 'custom_from_display_name' ); ?>">
1287 </fieldset>
1288
1289 </fieldset>
1290 </td>
1291 </tr>
1292 </tbody>
1293 </table>
1294
1295 <br>
1296 <hr>
1297
1298 <?php
1299 }
1300
1301 /**
1302 * Email settings
1303 */
1304 private function email_settings() {
1305 ?>
1306 <h1><?php esc_html_e( 'Email Templates', 'wp-2fa' ); ?></h1>
1307 <h3><?php esc_html_e( 'Enforced 2FA email', 'wp-2fa' ); ?></h3>
1308 <p class="description">
1309 <?php esc_html_e( 'This is the email sent to applicable users when you enforce 2fa.', 'wp-2fa' ); ?>
1310 </p>
1311 <table class="form-table">
1312 <tbody>
1313 <tr>
1314 <th><label for="2fa-method"><?php esc_html_e( 'Send this email', 'wp-2fa' ); ?></label>
1315 </th>
1316 <td>
1317 <fieldset>
1318 <input type="checkbox" id="send_enforced_email" name="send_enforced_email" value="enable_enforced_email"
1319 <?php checked( 'enable_enforced_email', WP2FA::get_wp2fa_email_templates( 'send_enforced_email' ), true ); ?>
1320 >
1321 <label for="send_enforced_email"><?php esc_html_e( 'Uncheck to disable this message.', 'wp-2fa' ); ?></label>
1322 </fieldset>
1323 </td>
1324 </tr>
1325 <tr>
1326 <th><label for="2fa-method"><?php esc_html_e( 'Email subject', 'wp-2fa' ); ?></label>
1327 </th>
1328 <td>
1329 <fieldset>
1330 <input type="text" id="enforced_email_subject" name="enforced_email_subject" class="large-text" value="<?php esc_html_e( WP2FA::get_wp2fa_email_templates( 'enforced_email_subject' ) ) ?>">
1331 </fieldset>
1332 </td>
1333 </tr>
1334 <tr>
1335 <th><label for="2fa-method"><?php esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
1336 </br>
1337 <label for="2fa-method" style="font-weight: 400;"><?php esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
1338 </br></br>
1339 <span style="font-weight: 400;">
1340 {site_url}</br>
1341 {site_name}</br>
1342 {grace_period}</br>
1343 {user_login_name}</br>
1344 {login_code}
1345 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) ) {
1346 echo '</br>{2fa_settings_page_url}';
1347 } ?>
1348 </span>
1349 </th>
1350 <td>
1351 <fieldset>
1352 <?php
1353 $message = WP2FA::get_wp2fa_email_templates( 'enforced_email_body' );
1354 $content = $message;
1355 $editor_id = 'enforced_email_body';
1356 $settings = array(
1357 'media_buttons' => false,
1358 'editor_height' => 200,
1359 );
1360 wp_editor( $content, $editor_id, $settings );
1361 ?>
1362 </fieldset>
1363 </td>
1364 </tr>
1365 </tbody>
1366 </table>
1367
1368 <br>
1369 <hr>
1370
1371 <h3><?php esc_html_e( 'Login code email', 'wp-2fa' ); ?></h3>
1372 <p class="description">
1373 <?php esc_html_e( 'This is the email sent to a user when a login code is required.', 'wp-2fa' ); ?>
1374 </p>
1375 <table class="form-table">
1376 <tbody>
1377 <tr>
1378 <th><label for="2fa-method"><?php esc_html_e( 'Email subject', 'wp-2fa' ); ?></label>
1379 </th>
1380 <td>
1381 <fieldset>
1382 <input type="text" id="login_code_email_subject" name="login_code_email_subject" class="large-text" value="<?php esc_html_e( WP2FA::get_wp2fa_email_templates( 'login_code_email_subject' ) ) ?>">
1383 </fieldset>
1384 </td>
1385 </tr>
1386 <tr>
1387 <th><label for="2fa-method"><?php esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
1388 </br>
1389 <label for="2fa-method" style="font-weight: 400;"><?php esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
1390 </br></br>
1391 <span style="font-weight: 400;">
1392 {site_url}</br>
1393 {site_name}</br>
1394 {grace_period}</br>
1395 {user_login_name}</br>
1396 {login_code}
1397 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) ) {
1398 echo '</br>{2fa_settings_page_url}';
1399 } ?>
1400 </span>
1401 </th>
1402 <td>
1403 <fieldset>
1404 <?php
1405 $message = WP2FA::get_wp2fa_email_templates( 'login_code_email_body' );
1406 $content = $message;
1407 $editor_id = 'login_code_email_body';
1408 $settings = array(
1409 'media_buttons' => false,
1410 'editor_height' => 200,
1411 );
1412 wp_editor( $content, $editor_id, $settings );
1413 ?>
1414 </fieldset>
1415 </td>
1416 </tr>
1417 </tbody>
1418 </table>
1419
1420 <br>
1421 <hr>
1422
1423 <h3><?php esc_html_e( 'User account locked email', 'wp-2fa' ); ?></h3>
1424 <p class="description">
1425 <?php esc_html_e( 'This is the email sent to a user upon grace period expiry.', 'wp-2fa' ); ?>
1426 </p>
1427 <table class="form-table">
1428 <tbody>
1429 <tr>
1430 <th><label for="2fa-method"><?php esc_html_e( 'Send this email', 'wp-2fa' ); ?></label>
1431 </th>
1432 <td>
1433 <fieldset>
1434 <input type="checkbox" id="send_account_locked_email" name="send_account_locked_email" value="enable_account_locked_email"
1435 <?php checked( 'enable_account_locked_email', WP2FA::get_wp2fa_email_templates( 'send_account_locked_email' ), true ); ?>
1436 >
1437 <label for="send_account_locked_email"><?php esc_html_e( 'Uncheck to disable this message.', 'wp-2fa' ); ?></label>
1438 </fieldset>
1439 </td>
1440 </tr>
1441 <tr>
1442 <th><label for="2fa-method"><?php esc_html_e( 'Email subject', 'wp-2fa' ); ?></label>
1443 </th>
1444 <td>
1445 <fieldset>
1446 <input type="text" id="user_account_locked_email_subject" name="user_account_locked_email_subject" class="large-text" value="<?php esc_html_e( WP2FA::get_wp2fa_email_templates( 'user_account_locked_email_subject' ) ) ?>">
1447 </fieldset>
1448 </td>
1449 </tr>
1450 <tr>
1451 <th><label for="2fa-method"><?php esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
1452 </br>
1453 <label for="2fa-method" style="font-weight: 400;"><?php esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
1454 </br></br>
1455 <span style="font-weight: 400;">
1456 {site_url}</br>
1457 {site_name}</br>
1458 {grace_period}</br>
1459 {user_login_name}</br>
1460 {login_code}
1461 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) ) {
1462 echo '</br>{2fa_settings_page_url}';
1463 } ?>
1464 </span>
1465 </th>
1466 <td>
1467 <fieldset>
1468 <?php
1469 $message = WP2FA::get_wp2fa_email_templates( 'user_account_locked_email_body' );
1470 $content = $message;
1471 $editor_id = 'user_account_locked_email_body';
1472 $settings = array(
1473 'media_buttons' => false,
1474 'editor_height' => 200,
1475 );
1476 wp_editor( $content, $editor_id, $settings );
1477 ?>
1478 </fieldset>
1479 </td>
1480 </tr>
1481 </tbody>
1482 </table>
1483
1484 <br>
1485 <hr>
1486
1487 <h3><?php esc_html_e( 'User account unlocked email', 'wp-2fa' ); ?></h3>
1488 <p class="description">
1489 <?php esc_html_e( 'This is the email sent to a user when the user\'s account has been unlocked.', 'wp-2fa' ); ?>
1490 </p>
1491 <table class="form-table">
1492 <tbody>
1493 <tr>
1494 <th><label for="2fa-method"><?php esc_html_e( 'Send this email', 'wp-2fa' ); ?></label>
1495 </th>
1496 <td>
1497 <fieldset>
1498 <input type="checkbox" id="send_account_unlocked_email" name="send_account_unlocked_email" value="enable_account_unlocked_email"
1499 <?php checked( 'enable_account_unlocked_email', WP2FA::get_wp2fa_email_templates( 'send_account_unlocked_email' ), true ); ?>
1500 >
1501 <label for="send_account_unlocked_email"><?php esc_html_e( 'Uncheck to disable this message.', 'wp-2fa' ); ?></label>
1502 </fieldset>
1503 </td>
1504 </tr>
1505 <tr>
1506 <th><label for="2fa-method"><?php esc_html_e( 'Email subject', 'wp-2fa' ); ?></label>
1507 </th>
1508 <td>
1509 <fieldset>
1510 <input type="text" id="user_account_unlocked_email_subject" name="user_account_unlocked_email_subject" class="large-text" value="<?php esc_html_e( WP2FA::get_wp2fa_email_templates( 'user_account_unlocked_email_subject' ) ) ?>">
1511 </fieldset>
1512 </td>
1513 </tr>
1514 <tr>
1515 <th><label for="2fa-method"><?php esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
1516 </br>
1517 <label for="2fa-method" style="font-weight: 400;"><?php esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
1518 </br></br>
1519 <span style="font-weight: 400;">
1520 {site_url}</br>
1521 {site_name}</br>
1522 {grace_period}</br>
1523 {user_login_name}</br>
1524 {login_code}
1525 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) ) {
1526 echo '</br>{2fa_settings_page_url}';
1527 } ?>
1528 </span>
1529 </th>
1530 <td>
1531 <fieldset>
1532 <?php
1533 $message = WP2FA::get_wp2fa_email_templates( 'user_account_unlocked_email_body' );
1534 $content = $message;
1535 $editor_id = 'user_account_unlocked_email_body';
1536 $settings = array(
1537 'media_buttons' => false,
1538 'editor_height' => 200,
1539 );
1540 wp_editor( $content, $editor_id, $settings );
1541 ?>
1542 </fieldset>
1543 </td>
1544 </tr>
1545 </tbody>
1546 </table>
1547 <?php
1548 }
1549
1550 /**
1551 * Validate email templates before saving
1552 *
1553 * @param array $input The settings array.
1554 */
1555 public function validate_and_sanitize_email( $input ) {
1556
1557 // Bail if user doesnt have permissions to be here.
1558 if ( ! current_user_can( 'manage_options' ) ) {
1559 return;
1560 }
1561
1562 if ( empty( $_POST ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'wp_2fa_email_settings-options' ) && ! wp_verify_nonce( $_POST['_wpnonce'], 'wp_2fa_settings-options' ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'wp_2fa_email_settings-options' ) && ! wp_verify_nonce( $_POST['_wpnonce'], 'wp_2fa_settings-options' ) ) {
1563 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
1564 }
1565
1566 if ( isset( $_POST['email_from_setting'] ) && 'use-defaults' === $_POST['email_from_setting'] || isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] ) {
1567 $output['email_from_setting'] = sanitize_text_field( wp_unslash( $_POST['email_from_setting'] ) );
1568 }
1569
1570 if ( isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_email_address'] ) && empty( $_POST['custom_from_email_address'] ) ) {
1571 add_settings_error(
1572 'wp_2fa_settings',
1573 esc_attr( 'email_from_settings_error' ),
1574 esc_html__( 'Please provide an email address', 'wp-2fa' ),
1575 'error'
1576 );
1577 $output['custom_from_email_address'] = '';
1578 }
1579
1580 if ( isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] && isset( $_POST['custom_from_display_name'] ) && empty( $_POST['custom_from_display_name'] ) ) {
1581 add_settings_error(
1582 'wp_2fa_settings',
1583 esc_attr( 'display_name_settings_error' ),
1584 esc_html__( 'Please provide a display name.', 'wp-2fa' ),
1585 'error'
1586 );
1587 $output['custom_from_email_address'] = '';
1588 }
1589
1590
1591 if ( isset( $_POST['custom_from_email_address'] ) && ! empty( $_POST['custom_from_email_address'] ) ) {
1592 if ( ! filter_var( $_POST['custom_from_email_address'], FILTER_VALIDATE_EMAIL ) ) {
1593 add_settings_error(
1594 'wp_2fa_settings',
1595 esc_attr( 'email_invalid_settings_error' ),
1596 esc_html__( 'Please provide a valid email address. Your email address has not been updated.', 'wp-2fa' ),
1597 'error'
1598 );
1599 }
1600 $output['custom_from_email_address'] = sanitize_email( wp_unslash( $_POST['custom_from_email_address'] ) );
1601 }
1602
1603 if ( isset( $_POST['custom_from_display_name'] ) && ! empty( $_POST['custom_from_display_name'] ) ) {
1604 // Check if the string contains HTML/tags.
1605 preg_match( "/<\/?\w+((\s+\w+(\s*=\s*(?:\".*?\"|'.*?'|[^'\">\s]+))?)+\s*|\s*)\/?>/", $_POST['custom_from_display_name'], $matches );
1606 if ( count( $matches ) > 0 ) {
1607 add_settings_error(
1608 'wp_2fa_settings',
1609 esc_attr( 'display_name_invalid_settings_error' ),
1610 esc_html__( 'Please only use alphanumeric text. Your display name has not been updated.', 'wp-2fa' ),
1611 'error'
1612 );
1613 } else {
1614 $output['custom_from_display_name'] = sanitize_text_field( wp_unslash( $_POST['custom_from_display_name'] ) );
1615 }
1616 }
1617
1618 if ( isset( $_POST['enforced_email_subject'] ) ) {
1619 $output['enforced_email_subject'] = wp_kses_post( wp_unslash( $_POST['enforced_email_subject'] ) );
1620 }
1621
1622 if ( isset( $_POST['enforced_email_body'] ) ) {
1623 $output['enforced_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['enforced_email_body'] ) ) );
1624 }
1625
1626 if ( isset( $_POST['login_code_email_subject'] ) ) {
1627 $output['login_code_email_subject'] = wp_kses_post( wp_unslash( $_POST['login_code_email_subject'] ) );
1628 }
1629
1630 if ( isset( $_POST['login_code_email_body'] ) ) {
1631 $output['login_code_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['login_code_email_body'] ) ) );
1632 }
1633
1634 if ( isset( $_POST['user_account_locked_email_subject'] ) ) {
1635 $output['user_account_locked_email_subject'] = wp_kses_post( wp_unslash( $_POST['user_account_locked_email_subject'] ) );
1636 }
1637
1638 if ( isset( $_POST['user_account_locked_email_body'] ) ) {
1639 $output['user_account_locked_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['user_account_locked_email_body'] ) ) );
1640 }
1641
1642 if ( isset( $_POST['user_account_unlocked_email_subject'] ) ) {
1643 $output['user_account_unlocked_email_subject'] = wp_kses_post( wp_unslash( $_POST['user_account_unlocked_email_subject'] ) );
1644 }
1645
1646 if ( isset( $_POST['user_account_unlocked_email_body'] ) ) {
1647 $output['user_account_unlocked_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['user_account_unlocked_email_body'] ) ) );
1648 }
1649
1650 if ( isset( $_POST['send_enforced_email'] ) && 'enable_enforced_email' === $_POST['send_enforced_email'] ) {
1651 $output['send_enforced_email'] = sanitize_text_field( $_POST['send_enforced_email'] );
1652 }
1653
1654 if ( isset( $_POST['send_account_locked_email'] ) && 'enable_account_locked_email' === $_POST['send_account_locked_email'] ) {
1655 $output['send_account_locked_email'] = sanitize_text_field( $_POST['send_account_locked_email'] );
1656 }
1657
1658 if ( isset( $_POST['send_account_unlocked_email'] ) && 'enable_account_unlocked_email' === $_POST['send_account_unlocked_email'] ) {
1659 $output['send_account_unlocked_email'] = sanitize_text_field( $_POST['send_account_unlocked_email'] );
1660 }
1661
1662 // Remove duplicates from settings errors. We do this as this sanitization callback is actually fired twice, so we end up with duplicates when saving the settings for the FIRST TIME only. The issue is not present once the settings are in the DB as the sanitization wont fire again. For details on this core issue - https://core.trac.wordpress.org/ticket/21989.
1663 global $wp_settings_errors;
1664 if ( isset( $wp_settings_errors ) ) {
1665 $errors = array_map( 'unserialize', array_unique( array_map( 'serialize', $wp_settings_errors ) ) );
1666 $wp_settings_errors = $errors;
1667 }
1668
1669 if ( isset( $output ) ) {
1670 return $output;
1671 } else {
1672 return;
1673 }
1674
1675 }
1676
1677 /**
1678 * Creates a new page with our shortcode present.
1679 */
1680 public function generate_custom_user_profile_page( $page_slug ) {
1681 // Bail if user doesnt have permissions to be here.
1682 if ( ! current_user_can( 'manage_options' ) ) {
1683 return;
1684 }
1685
1686 // Check if a page with slug exists.
1687 $page_exists = $this->get_post_by_post_name( $page_slug, 'page' );
1688 if ( $page_exists ) {
1689 // Seeing as the page exisits, return its ID.
1690 return $page_exists->ID;
1691 }
1692
1693 $generated_by_message = sprintf(
1694 /* translators: %1$s: is the user name, %2$s is the website address */
1695 '<p>%1$s <a href="https://www.wpwhitesecurity.com/wordpress-plugins/wp-2fa/" target="_blank">%2$s</a></p>',
1696 esc_html__( 'Page generated by', 'wp-2fa' ),
1697 esc_html__( 'WP 2FA Plugin', 'wp-2fa' )
1698 );
1699
1700 $user = wp_get_current_user();
1701 $post_data = array(
1702 'post_title' => 'WP 2FA User Profile',
1703 'post_name' => $page_slug,
1704 'post_content' => '[wp-2fa-setup-form] ' . $generated_by_message,
1705 'post_status' => 'publish',
1706 'post_author' => $user->ID,
1707 'post_type' => 'page',
1708 );
1709
1710 // Lets insert the post now.
1711 $result = wp_insert_post( $post_data );
1712
1713 if ( $result && ! is_wp_error( $result ) ) {
1714 $post_id = $result;
1715 set_transient( 'wp_2fa_new_custom_page_created', true, 1 );
1716 set_site_transient( 'wp_2fa_new_custom_page_created', true, 1 );
1717 return $post_id;
1718 }
1719 }
1720
1721 /**
1722 * Check if page with slug exisits.
1723 */
1724 public function get_post_by_post_name( $slug = '', $post_type = '' ) {
1725 if ( ! $slug || ! $post_type ) {
1726 return false;
1727 }
1728
1729 $post_object = get_page_by_path( $slug, OBJECT, $post_type );
1730
1731 if ( ! $post_object ) {
1732 return false;
1733 }
1734
1735 return $post_object;
1736 }
1737
1738 /**
1739 * Add our custom state to our created page.
1740 */
1741 public function add_display_post_states( $post_states, $post ) {
1742 if ( ! empty( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) ) {
1743 if ( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) === $post->ID ) {
1744 $post_states['wp_2fa_page_for_user'] = __( 'WP 2FA User Page', 'wp-2fa' );
1745 }
1746 }
1747
1748 return $post_states;
1749 }
1750 }
1751