PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 1.2.0
WP 2FA – Two-factor authentication for WordPress v1.2.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
1412 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 <div class="wrap">
80 <h2><?php esc_html_e( 'WP 2FA Settings', 'wp-2fa' ); ?></h2>
81 <hr>
82 <?php if ( ! empty( WP2FA::get_wp2fa_setting( 'limit_access' ) ) && $main_user !== $user->ID ) { ?>
83
84 <?php
85 echo esc_html__( 'These settings have been disabled by your site administrator, please contact them for further assistance.', 'wp-2fa' );
86 ?>
87
88 <?php } else { ?>
89
90 <div class="nav-tab-wrapper">
91 <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>
92 <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>
93 </div>
94 <?php
95 if ( ! current_user_can( 'manage_options' ) ) {
96 return;
97 }
98 if ( WP2FA::is_this_multisite() ) {
99 $action = 'edit.php?action=update_wp2fa_network_options';
100 } else {
101 $action = 'options.php';
102 }
103 if ( ! isset( $_REQUEST['tab'] ) || isset( $_REQUEST['tab'] ) && '2fa-settings' === $_REQUEST['tab'] ) : ?>
104 <br/>
105 <?php
106 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' ) );
107 ?>
108 <br/>
109 <form action='<?php echo esc_attr( $action ) ?>' method='post' autocomplete="off">
110 <?php
111 if ( ! current_user_can( 'manage_options' ) ) {
112 return;
113 }
114
115 settings_fields( 'wp_2fa_settings' );
116 $this->select_method_setting();
117 $this->select_enforcment_policy_setting();
118 $this->excluded_roles_or_users_setting();
119 if ( WP2FA::is_this_multisite() ) {
120 $this->excluded_network_sites();
121 }
122 $this->grace_period_setting();
123 $this->limit_settings_access();
124 $this->remove_data_upon_uninstall();
125 submit_button();
126 ?>
127 </form>
128 <?php endif; ?>
129
130 <?php
131 if ( WP2FA::is_this_multisite() ) {
132 $action = 'edit.php?action=update_wp2fa_network_email_options';
133 } else {
134 $action = 'options.php';
135 }
136 ?>
137
138 <?php if ( isset( $_REQUEST['tab'] ) && 'email-settings' === $_REQUEST['tab'] ) : ?>
139 <br/>
140 <?php
141 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' ) );
142 ?>
143 <br/>
144 <form action='<?php echo esc_attr( $action ) ?>' method='post' autocomplete="off">
145 <?php
146 if ( ! current_user_can( 'manage_options' ) ) {
147 return;
148 }
149
150 settings_fields( 'wp_2fa_email_settings' );
151 $this->email_from_settings();
152 $this->email_settings();
153 submit_button( 'Save email settings and templates' );
154 ?>
155 </form>
156 <?php endif; ?>
157
158 <?php } ?>
159 </div>
160 <?php
161 }
162
163 /**
164 * General settings
165 */
166 private function select_method_setting() {
167 ?>
168 <h3><?php esc_html_e( 'Which two-factor authentication methods can your users use on this website?', 'wp-2fa' ); ?></h3>
169 <p class="description">
170 <?php esc_html_e( 'When you disable one of the below 2FA methods none of your users can use it.', 'wp-2fa' ); ?>
171 </p>
172 <table class="form-table">
173 <tbody>
174 <tr>
175 <th><label for="2fa-method"><?php esc_html_e( 'Select the methods:', 'wp-2fa' ); ?></label></th>
176 <td>
177 <fieldset>
178 <label for="totp">
179 <input type="checkbox" id="totp" name="wp_2fa_settings[enable_totp]" value="enable_totp"
180 <?php checked( 'enable_totp', WP2FA::get_wp2fa_setting( 'enable_totp' ), true ); ?>
181 >
182 <?php esc_html_e( 'one-time code via Google authenticator app (TOTP)', 'wp-2fa' ); ?>
183 </label>
184 <br/>
185 <label for="email">
186 <input type="checkbox" id="hotp" name="wp_2fa_settings[enable_email]" value="enable_email"
187 <?php checked( WP2FA::get_wp2fa_setting( 'enable_email' ), 'enable_email' ); ?>
188 >
189 <?php esc_html_e( 'one-time code via email (HOTP)', 'wp-2fa' ); ?>
190 </label>
191 <br />
192 </fieldset>
193 </td>
194 </tr>
195 </tbody>
196 </table>
197 <?php
198 }
199
200 /**
201 * Policy settings
202 */
203 private function select_enforcment_policy_setting() {
204 ?>
205 <h3><?php esc_html_e( 'Do you want to enforce 2FA for some, or all the users? ', 'wp-2fa' ); ?></h3>
206 <p class="description">
207 <?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>
208 </p>
209 <table class="form-table">
210 <tbody>
211 <tr>
212 <th><label for="enforcment-policy"><?php esc_html_e( 'Enforce 2FA on:', 'wp-2fa' ); ?></label></th>
213 <td>
214 <fieldset class="contains-hidden-inputs">
215 <label for="all-users">
216 <input type="radio" name="wp_2fa_settings[enforcment-policy]" id="all-users" value="all-users"
217 <?php checked( WP2FA::get_wp2fa_setting( 'enforcment-policy' ), 'all-users' ); ?>
218 >
219 <span><?php esc_html_e( 'All users', 'wp-2fa' ); ?></span>
220 </label>
221
222 <br/>
223 <label for="certain-roles-only">
224 <input type="radio" name="wp_2fa_settings[enforcment-policy]" id="certain-roles-only" value="certain-roles-only"
225 <?php checked( WP2FA::get_wp2fa_setting( 'enforcment-policy' ), 'certain-roles-only' ); ?>
226 data-unhide-when-checked=".certain-roles-only-inputs">
227 <span><?php esc_html_e( 'Only on users with these roles', 'wp-2fa' ); ?></span>
228 </label>
229 <fieldset class="hidden certain-roles-only-inputs">
230 <br/>
231 <input type="text" id="enforced_roles_search" placeholder="Search roles">
232 <input type="hidden" id="enforced_roles" name="wp_2fa_settings[enforced_roles]" value="<?php echo esc_attr( WP2FA::get_wp2fa_setting( 'enforced_roles' ) ); ?>">
233 <div id="enforced_roles_buttons"></div>
234 </fieldset>
235
236 <br/>
237 <label for="certain-users-only">
238 <input type="radio" name="wp_2fa_settings[enforcment-policy]" id="certain-users-only" value="certain-users-only"
239 <?php checked( WP2FA::get_wp2fa_setting( 'enforcment-policy' ), 'certain-users-only' ); ?>
240 data-unhide-when-checked=".certain-users-only-inputs">
241 <span><?php esc_html_e( 'Only on these users', 'wp-2fa' ); ?></span>
242 </label>
243 <fieldset class="hidden certain-users-only-inputs">
244 <br/>
245 <input type="text" id="enforced_users_search" placeholder="Search users">
246 <input type="hidden" id="enforced_users" name="wp_2fa_settings[enforced_users]" value="<?php echo esc_attr( WP2FA::get_wp2fa_setting( 'enforced_users' ) ); ?>">
247 <div id="enforced_users_buttons"></div>
248 </fieldset>
249 <br/>
250 <label for="do-not-enforce">
251 <input type="radio" name="wp_2fa_settings[enforcment-policy]" id="do-not-enforce" value="do-not-enforce"
252 <?php checked( WP2FA::get_wp2fa_setting( 'enforcment-policy' ), 'do-not-enforce' ); ?>
253 >
254 <span><?php esc_html_e( 'Do not enforce on any users', 'wp-2fa' ); ?></span>
255 </label>
256 <br/>
257 </fieldset>
258 </td>
259 </tr>
260 </tbody>
261 </table>
262 <?php
263 }
264
265 /**
266 * Role and users exclusion settings
267 */
268 private function excluded_roles_or_users_setting() {
269 ?>
270 <br>
271 <h3><?php esc_html_e( 'Do you want to exclude any users or roles from 2FA? ', 'wp-2fa' ); ?></h3>
272 <p class="description">
273 <?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' ); ?>
274 </p>
275 <table class="form-table">
276 <tbody>
277 <tr>
278 <th><label for="enforcment-policy"><?php esc_html_e( 'Exclude the following users', 'wp-2fa' ); ?></label></th>
279 <td>
280 <fieldset>
281 <input type="text" id="excluded_users_search" placeholder="Search user name">
282 <input type="hidden" id="excluded_users" name="wp_2fa_settings[excluded_users]"
283 value="<?php echo sanitize_text_field( WP2FA::get_wp2fa_setting( 'excluded_users' ) ); ?>">
284 <div id="excluded_users_buttons"></div>
285 </fieldset>
286 </td>
287 </tr>
288 <tr>
289 <th><label for="enforcment-policy"><?php esc_html_e( 'Exclude the following roles:', 'wp-2fa' ); ?></label></th>
290 <td>
291 <fieldset>
292 <input type="text" id="excluded_roles_search" placeholder="Search roles">
293 <input type="hidden" id="excluded_roles" name="wp_2fa_settings[excluded_roles]"
294 value="<?php echo sanitize_text_field( WP2FA::get_wp2fa_setting( 'excluded_roles' ) ); ?>">
295 <div id="excluded_roles_buttons"></div>
296 </fieldset>
297 </td>
298 </tr>
299 </tbody>
300 </table>
301 <?php
302 }
303
304 /**
305 * Role and users exclusion settings
306 */
307 private function excluded_network_sites() {
308 ?>
309 <br>
310 <h3><?php esc_html_e( 'Do you want to exclude all the users of a site from 2FA? ', 'wp-2fa' ); ?></h3>
311 <p class="description">
312 <?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' ); ?>
313 </p>
314 <table class="form-table">
315 <tbody>
316 <tr>
317 <th><label for="enforcment-policy"><?php esc_html_e( 'Exclude the following sites', 'wp-2fa' ); ?></label></th>
318 <td>
319 <fieldset>
320 <input type="text" id="excluded_sites_search" placeholder="Search sites in your network">
321 <input type="hidden" id="excluded_sites" name="wp_2fa_settings[excluded_sites]"
322 value="<?php echo sanitize_text_field( WP2FA::get_wp2fa_setting( 'excluded_sites' ) ); ?>">
323 <div id="excluded_sites_buttons"></div>
324 </fieldset>
325 </td>
326 </tr>
327 </tbody>
328 </table>
329 <?php
330 }
331
332 /**
333 * Grace period settings
334 */
335 private function grace_period_setting() {
336 $user = wp_get_current_user();
337
338 $grace_period = (int) WP2FA::get_wp2fa_setting( 'grace-period' );
339 $testing = get_option( 'wp_2fa_test_grace' );
340 if ( '1' === $testing ) {
341 $grace_max = 600;
342 } else {
343 $grace_max = 10;
344 }
345 ?>
346 <br>
347 <h3><?php esc_html_e( 'How long should the grace period for your users be?', 'wp-2fa' ); ?></h3>
348 <p class="description">
349 <?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>
350 </p>
351 <table class="form-table">
352 <tbody>
353 <tr>
354 <th><label for="grace-period"><?php esc_html_e( 'Grace period', 'wp-2fa' ); ?></label></th>
355 <td>
356 <fieldset>
357 <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 ); ?>">
358 <label class="radio-inline">
359 <input type="radio" name="wp_2fa_settings[grace-period-denominator]" value="hours"
360 <?php checked( WP2FA::get_wp2fa_setting( 'grace-period-denominator' ), 'hours' ); ?>
361 >
362 <?php esc_html_e( 'Hours', 'wp-2fa' ); ?>
363 </label>
364 <label class="radio-inline">
365 <input type="radio" name="wp_2fa_settings[grace-period-denominator]" value="days"
366 <?php checked( WP2FA::get_wp2fa_setting( 'grace-period-denominator' ), 'days' ); ?>
367 >
368 <?php esc_html_e( 'Days', 'wp-2fa' ); ?>
369 </label>
370 <?php
371 $testing = get_option( 'wp_2fa_test_grace' );
372 if ( '1' === $testing ) {
373 ?>
374 <label class="radio-inline">
375 <input type="radio" name="wp_2fa_settings[grace-period-denominator]" value="seconds"
376 <?php checked( WP2FA::get_wp2fa_setting( 'grace-period-denominator' ), 'seconds' ); ?>
377 >
378 <?php esc_html_e( 'Seconds', 'wp-2fa' ); ?>
379 </label>
380 <?php
381 }
382
383 if ( ! empty( WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' ) ) ) {
384 $last_user_to_update_settings = WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' );
385 } else {
386 $last_user_to_update_settings = $user->ID;
387 }
388
389 ?>
390 <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 ); ?>">
391 </fieldset>
392 </td>
393 </tr>
394 </tbody>
395 </table>
396
397 <h3><?php esc_html_e( 'How often should the plugin check if a user\'s grace period is over?', 'wp-2fa' ); ?></h3>
398 <p class="description">
399 <?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' ); ?>
400 </p>
401 <table class="form-table">
402 <tbody>
403 <tr>
404 <th><label for="grace-period"><?php esc_html_e( 'Enable cron', 'wp-2fa' ); ?></label></th>
405 <td>
406 <fieldset>
407 <input type="checkbox" id="grace-cron" name="wp_2fa_settings[enable_grace_cron]" value="enable_grace_cron"
408 <?php checked( 1, WP2FA::get_wp2fa_setting( 'enable_grace_cron' ), true ); ?>
409 >
410 <?php esc_html_e( 'Use cron job to check grace periods', 'wp-2fa' ); ?>
411 </fieldset>
412 </td>
413 </tr>
414 <tr class="disabled destory-session-setting">
415 <th><label for="destory-session"><?php esc_html_e( 'Destroy session', 'wp-2fa' ); ?></label></th>
416 <td>
417 <fieldset>
418 <input type="checkbox" id="destory-session" name="wp_2fa_settings[enable_destroy_session]" value="enable_destroy_session"
419 <?php checked( 1, WP2FA::get_wp2fa_setting( 'enable_destroy_session' ), true ); ?>
420 >
421 <?php esc_html_e( 'Destory user session when grace period expires?', 'wp-2fa' ); ?>
422 </fieldset>
423 </td>
424 </tr>
425 </tbody>
426 </table>
427 <?php
428 }
429
430 /**
431 * Limit settings setting
432 */
433 private function limit_settings_access() {
434 ?>
435 <br>
436 <h3><?php esc_html_e( 'Limit 2FA settings access?', 'wp-2fa' ); ?></h3>
437 <p class="description">
438 <?php esc_html_e( 'Use this setting to hide this plugin configuration area from all other admins.', 'wp-2fa' ); ?>
439 </p>
440 <table class="form-table">
441 <tbody>
442 <tr>
443 <th><label for="grace-period"><?php esc_html_e( 'Limited access', 'wp-2fa' ); ?></label></th>
444 <td>
445 <fieldset>
446 <input type="checkbox" id="limit_access" name="wp_2fa_settings[limit_access]" value="limit_access"
447 <?php checked( 1, WP2FA::get_wp2fa_setting( 'limit_access' ), true ); ?>
448 >
449 <?php esc_html_e( 'Hide settings from other administrators', 'wp-2fa' ); ?>
450 </fieldset>
451 </td>
452 </tr>
453 </tbody>
454 </table>
455 <?php
456 }
457
458 /**
459 * Limit settings setting
460 */
461 private function remove_data_upon_uninstall() {
462 ?>
463 <div class="danger-zone-wrapper">
464 <h3><?php esc_html_e( 'Do you want to delete the plugin data from the database upon uninstall?', 'wp-2fa' ); ?></h3>
465 <p class="description">
466 <?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' ); ?>
467 </p>
468 <table class="form-table">
469 <tbody>
470 <tr>
471 <th><label for="delete_data"><?php esc_html_e( 'Delete data', 'wp-2fa' ); ?></label></th>
472 <td>
473 <fieldset>
474 <input type="checkbox" id="elete_data" name="wp_2fa_settings[delete_data_upon_uninstall]" value="delete_data_upon_uninstall"
475 <?php checked( 1, WP2FA::get_wp2fa_setting( 'delete_data_upon_uninstall' ), true ); ?>
476 >
477 <?php esc_html_e( 'Delete data upon uninstall', 'wp-2fa' ); ?>
478 </fieldset>
479 </td>
480 </tr>
481 </tbody>
482 </table>
483 </div>
484 <?php
485 }
486
487 /**
488 * Get all useers
489 */
490 public function get_all_users() {
491 // Die if user does not have permission to view.
492 if ( ! current_user_can( 'administrator' ) ) {
493 die( 'Access Denied.' );
494 }
495 // Filter $_GET array for security.
496 $get_array = filter_input_array( INPUT_GET );
497
498 // Die if nonce verification failed.
499 if ( ! wp_verify_nonce( sanitize_text_field( $get_array['wp_2fa_nonce'] ), 'wp-2fa-settings-nonce' ) ) {
500 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
501 }
502 // Fetch users.
503 $users = array();
504 if ( WP2FA::is_this_multisite() ) {
505 $users_args = array( 'blog_id' => 0 );
506 } else {
507 $users_args = array();
508 }
509
510 foreach ( get_users( $users_args ) as $user ) {
511 if ( strpos( $user->user_login, $get_array['term'] ) !== false ) {
512 array_push( $users, $user->user_login );
513 }
514 }
515 echo wp_json_encode( $users );
516 exit;
517 }
518
519 /**
520 * Get all network sites
521 */
522 public function get_all_network_sites() {
523 // Die if user does not have permission to view.
524 if ( ! current_user_can( 'administrator' ) ) {
525 die( 'Access Denied.' );
526 }
527 // Filter $_GET array for security.
528 $get_array = filter_input_array( INPUT_GET );
529 // Die if nonce verification failed.
530 if ( ! wp_verify_nonce( sanitize_text_field( $get_array['wp_2fa_nonce'] ), 'wp-2fa-settings-nonce' ) ) {
531 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
532 }
533 // Fetch sites.
534 $sites_found = array();
535
536 foreach ( get_sites() as $site ) {
537 $subsite_id = get_object_vars( $site )['blog_id'];
538 $subsite_name = get_blog_details( $subsite_id )->blogname;
539 $site_details = '';
540 $site_details[$subsite_id] = $subsite_name;
541 if ( stripos( $subsite_name, $get_array['term'] ) !== false ) {
542 $site_details = $subsite_name . ':' . $subsite_id;
543 array_push( $sites_found, $site_details );
544 }
545 }
546 echo wp_json_encode( $sites_found );
547 exit;
548 }
549
550 /**
551 * Unlock users accounts if they have overrun grace period
552 *
553 * @param int $user_id User ID.
554 */
555 public function unlock_account( $user_id ) {
556 // Die if user does not have permission to view.
557 if ( ! current_user_can( 'administrator' ) ) {
558 die( 'Access Denied.' );
559 }
560
561 $grace_period = WP2FA::get_wp2fa_setting( 'grace-period' );
562 $grace_period_denominator = WP2FA::get_wp2fa_setting( 'grace-period-denominator' );
563 $create_a_string = $grace_period . ' ' . $grace_period_denominator;
564 // Turn that string into a time.
565 $grace_expiry = strtotime( $create_a_string );
566
567 // Filter $_GET array for security.
568 $get_array = filter_input_array( INPUT_GET );
569 $nonce = sanitize_text_field( $get_array['wp_2fa_nonce'] );
570
571 // Die if nonce verification failed.
572 if ( ! wp_verify_nonce( $nonce, 'wp-2fa-unlock-account-nonce' ) ) {
573 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
574 }
575
576 if ( isset( $get_array['user_id'] ) ) {
577 $unlock = delete_user_meta( intval( $get_array['user_id'] ), 'wp_2fa_user_grace_period_expired' );
578 $notification = delete_user_meta( intval( $get_array['user_id'] ), 'wp_2fa_locked_account_notification' );
579 $update = update_user_meta( intval( $get_array['user_id'] ), 'wp_2fa_grace_period_expiry', $grace_expiry );
580 $this->send_account_unlocked_email( intval( $get_array['user_id'] ) );
581 add_action( 'admin_notices', array( $this, 'user_unlocked_notice' ) );
582 }
583 }
584
585 /**
586 * Remove user 2fa config
587 *
588 * @param int $user_id User ID.
589 */
590 public function remove_user_2fa( $user_id ) {
591 // Die if user does not have permission to view.
592 if ( ! current_user_can( 'read' ) ) {
593 die( 'Access Denied.' );
594 }
595
596 // Filter $_GET array for security.
597 $get_array = filter_input_array( INPUT_GET );
598 $nonce = sanitize_text_field( $get_array['wp_2fa_nonce'] );
599
600 if ( ! wp_verify_nonce( $nonce, 'wp-2fa-remove-user-2fa-nonce' ) ) {
601 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
602 }
603
604 if ( isset( $get_array['user_id'] ) ) {
605 $user_id = intval( $get_array['user_id'] );
606 $wipe_totp_key = delete_user_meta( $user_id, 'wp_2fa_totp_key' );
607 $wipe_backup_codes = delete_user_meta( $user_id, 'wp_2fa_backup_codes' );
608 $wipe_enabled_methods = delete_user_meta( $user_id, 'wp_2fa_enabled_methods' );
609 $wipe_grace_period = delete_user_meta( $user_id, 'wp_2fa_grace_period_expiry' );
610 $wipe_email_address = delete_user_meta( $user_id, 'wp_2fa_nominated_email_address' );
611 $is_needed = Authentication::is_user_eligible_for_2fa( $user_id );
612 if ( $is_needed ) {
613 if ( 'do-not-enforce' !== WP2FA::get_wp2fa_setting( 'enforcment-policy' ) ) {
614 // Turn inputs into a useable string.
615 $create_a_string = WP2FA::get_wp2fa_setting( 'grace-period' ) . ' ' . WP2FA::get_wp2fa_setting( 'grace-period-denominator' );
616 // Turn that string into a time.
617 $grace_expiry = strtotime( $create_a_string );
618 update_user_meta( $user_id, 'wp_2fa_grace_period_expiry', $grace_expiry );
619 update_user_meta( $user_id, 'wp_2fa_update_nag_dismissed', true );
620 }
621 }
622 if ( isset( $get_array['admin_reset'] ) ) {
623 add_action( 'admin_notices', array( $this, 'admin_deleted_2fa_notice' ) );
624 } else {
625 add_action( 'admin_notices', array( $this, 'user_deleted_2fa_notice' ) );
626 }
627 }
628 }
629
630 /**
631 * Send account unlocked notification via email.
632 *
633 * @param int $user_id user ID.
634 */
635 public static function send_account_unlocked_email( $user_id ) {
636 // Grab user data.
637 $user = get_userdata( $user_id );
638 // Grab user email.
639 $email = $user->user_email;
640 // Setup the email contents.
641 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_account_unlocked_email_subject' ) ) );
642 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_account_unlocked_email_body' ), $user_id ) );
643 // Specify our desired headers.
644 $headers = 'Content-type: text/html;charset=utf-8' . "\r\n";
645
646 if ( 'use-custom-email' === WP2FA::get_wp2fa_email_templates( 'email_from_setting' ) ) {
647 $headers .= "From: ". WP2FA::get_wp2fa_email_templates( 'custom_from_display_name' ) ." <". WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' ) .">" . "\r\n";
648 }
649
650 // Fire our email.
651 $mail = wp_mail( $user->user_email, $subject, $message, $headers );
652 }
653
654 /**
655 * Validate options before saving
656 *
657 * @param array $input The settings array.
658 */
659 public function validate_and_sanitize( $input ) {
660 // Bail if user doesnt have permissions to be here.
661 if ( ! current_user_can( 'manage_options' ) ) {
662 return;
663 }
664
665 // Setup args we may need, depending if this is a MS setup or not.
666 $users = array();
667 if ( WP2FA::is_this_multisite() ) {
668 $users_args = array( 'blog_id' => 0 );
669 } else {
670 $users_args = array();
671 }
672
673 $users = get_users( $users_args );
674
675 if ( ! isset( $input['enable_totp'] ) && ! isset( $input['enable_email'] ) ) {
676 add_settings_error(
677 'wp_2fa_settings',
678 esc_attr( 'settings_error' ),
679 esc_html__( 'At least one 2FA method should be enabled.', 'wp-2fa' ),
680 'error'
681 );
682 }
683
684 // Compare current to old value to see if a method which was once enabled, has now been disabled.
685 if ( ! isset( $input['enable_totp'] ) && 'enable_totp' === WP2FA::get_wp2fa_setting( 'enable_totp' ) ) {
686 foreach ( $users as $user ) {
687 $enabled = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
688 if ( 'totp' === $enabled ) {
689 delete_user_meta( $user->ID, 'wp_2fa_enabled_methods', 'totp' );
690 update_user_meta( $user->ID, 'wp_2fa_user_needs_to_reconfigure_2fa', true );
691 }
692 }
693 }
694 if ( ! isset( $input['enable_email'] ) && 'enable_email' === WP2FA::get_wp2fa_setting( 'enable_email' ) ) {
695 foreach ( $users as $user ) {
696 $enabled = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
697 if ( 'email' === $enabled ) {
698 delete_user_meta( $user->ID, 'wp_2fa_enabled_methods', 'email' );
699 update_user_meta( $user->ID, 'wp_2fa_user_needs_to_reconfigure_2fa', true );
700 }
701 }
702 }
703
704 if ( isset( $input['enable_totp'] ) && 'enable_totp' === $input['enable_totp'] ) {
705 $output['enable_totp'] = sanitize_text_field( $input['enable_totp'] );
706 }
707
708 if ( isset( $input['enable_email'] ) && 'enable_email' === $input['enable_email'] ) {
709 $output['enable_email'] = sanitize_text_field( $input['enable_email'] );
710 }
711
712 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'] ) {
713 // Clear enforced roles/users if setting has changed.
714 if ( 'certain-users-only' === $input['enforcment-policy'] ) {
715 $input['enforced_roles'] = '';
716 }
717 if ( 'certain-roles-only' === $input['enforcment-policy'] ) {
718 $input['enforced_users'] = '';
719 }
720 if ( 'all-users' === $input['enforcment-policy'] ) {
721 $input['enforced_users'] = '';
722 $input['enforced_roles'] = '';
723 }
724
725 $output['enforcment-policy'] = sanitize_text_field( $input['enforcment-policy'] );
726 }
727
728 if ( WP2FA::get_wp2fa_setting( 'enforcment-policy' ) !== $input['enforcment-policy'] && 'do-not-enforce' === $input['enforcment-policy'] ) {
729 $input['enforced_users'] = '';
730 $input['enforced_roles'] = '';
731 }
732
733 if ( 'certain-roles-only' === $input['enforcment-policy'] && empty( $input['enforced_roles'] ) ) {
734 add_settings_error(
735 'wp_2fa_settings',
736 esc_attr( 'settings_error' ),
737 esc_html__( 'You must specify at least one role.', 'wp-2fa' ),
738 'error'
739 );
740 }
741
742 if ( 'certain-users-only' === $input['enforcment-policy'] && empty( $input['enforced_users'] ) ) {
743 add_settings_error(
744 'wp_2fa_settings',
745 esc_attr( 'settings_error' ),
746 esc_html__( 'You must specify at least one user.', 'wp-2fa' ),
747 'error'
748 );
749 }
750
751 if ( isset( $input['enforced_roles'] ) ) {
752 $output['enforced_roles'] = trim( sanitize_text_field( $input['enforced_roles'] ) );
753 }
754
755 if ( isset( $input['enforced_users'] ) ) {
756 $output['enforced_users'] = trim( sanitize_text_field( $input['enforced_users'] ) );
757 }
758
759 if ( isset( $input['excluded_users'] ) ) {
760 $output['excluded_users'] = trim( sanitize_text_field( $input['excluded_users'] ) );
761
762 // Wipe user 2fa data.
763 $user_array = explode( ',', $output['excluded_users'] );
764 foreach ( $user_array as $user ) {
765 if ( ! empty( $user ) ) {
766 $user_to_wipe = get_user_by( 'login', $user );
767 $wipe_totp_key = delete_user_meta( $user_to_wipe->ID, 'wp_2fa_totp_key' );
768 $wipe_backup_codes = delete_user_meta( $user_to_wipe->ID, 'wp_2fa_backup_codes' );
769 $wipe_enabled_methods = delete_user_meta( $user_to_wipe->ID, 'wp_2fa_enabled_methods' );
770 $wipe_grace_period = delete_user_meta( $user_to_wipe->ID, 'wp_2fa_grace_period_expiry' );
771 }
772 }
773 }
774
775 if ( isset( $input['excluded_roles'] ) ) {
776 $output['excluded_roles'] = trim( sanitize_text_field( $input['excluded_roles'] ) );
777
778 // Wipe user 2fa data.
779 $excluded_roles_array = array_filter( explode( ',', strtolower( $output['excluded_roles'] ) ) );
780 foreach ( $users as $user ) {
781 // Compare the user roles to the ones we are excluding and see if we get a match.
782 $result = array_intersect( $excluded_roles_array, $user->roles );
783 // If we do, lets wipe!
784 if ( ! empty( $result ) ) {
785 $wipe_totp_key = delete_user_meta( $user->ID, 'wp_2fa_totp_key' );
786 $wipe_backup_codes = delete_user_meta( $user->ID, 'wp_2fa_backup_codes' );
787 $wipe_enabled_methods = delete_user_meta( $user->ID, 'wp_2fa_enabled_methods' );
788 $wipe_grace_period = delete_user_meta( $user->ID, 'wp_2fa_grace_period_expiry' );
789 }
790 }
791 }
792
793 if ( WP2FA::is_this_multisite() ) {
794 if ( isset( $input['excluded_sites'] ) ) {
795 $output['excluded_sites'] = trim( sanitize_text_field( $input['excluded_sites'] ) );
796 }
797 } else {
798 $output['excluded_sites'] = '';
799 }
800
801 if ( isset( $input['grace-period'] ) ) {
802 if ( 0 === (int) $input['grace-period'] ) {
803 add_settings_error(
804 'wp_2fa_settings',
805 esc_attr( 'settings_error' ),
806 esc_html__( 'Grace period must be at least 1 day/hour', 'wp-2fa' ),
807 'error'
808 );
809 $output['grace-period'] = 1;
810 } else {
811 $output['grace-period'] = (int) $input['grace-period'];
812 }
813 }
814
815 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'] ) {
816 $output['grace-period-denominator'] = sanitize_text_field( $input['grace-period-denominator'] );
817 }
818
819 if ( isset( $input['enable_grace_cron'] ) ) {
820 $output['enable_grace_cron'] = (bool) $input['enable_grace_cron'];
821 }
822
823 if ( isset( $input['enable_destroy_session'] ) ) {
824 $output['enable_destroy_session'] = (bool) $input['enable_destroy_session'];
825 }
826
827 if ( isset( $input['2fa_settings_last_updated_by'] ) ) {
828 $output['2fa_settings_last_updated_by'] = esc_attr( trim( $input['2fa_settings_last_updated_by'] ) );
829 }
830
831 if ( isset( $input['limit_access'] ) ) {
832 $output['limit_access'] = (bool) $input['limit_access'];
833 }
834
835 if ( isset( $input['delete_data_upon_uninstall'] ) ) {
836 $output['delete_data_upon_uninstall'] = (bool) $input['delete_data_upon_uninstall'];
837 }
838
839 if ( isset( $input['grace-period'] ) && isset( $input['grace-period-denominator'] ) ) {
840 // Turn inputs into a useable string.
841 $create_a_string = $output['grace-period'] . ' ' . $output['grace-period-denominator'];
842 // Turn that string into a time.
843 $grace_expiry = strtotime( $create_a_string );
844 $output['grace-period-expiry-time'] = sanitize_text_field( $grace_expiry );
845 }
846
847 // Fetch users and apply the grace period tp their user meta.
848 if ( isset( $input['enforcment-policy'] ) && 'do-not-enforce' !== $input['enforcment-policy'] && ! isset( $input['grace-period-expiry-time'] ) ) {
849 // Flush the old expiry away from ALL users, we will re-apply them based on the current setup at the end of this.
850 foreach ( $users as $user ) {
851 delete_user_meta( $user->ID, 'wp_2fa_grace_period_expiry' );
852 }
853 // 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.
854 if ( isset( $input['enforcment-policy'] ) && 'certain-users-only' === $input['enforcment-policy'] && isset( $input['enforced_users'] ) && WP2FA::get_wp2fa_setting( 'enforced_users' ) !== $input['enforced_users'] ) {
855 $enforced_users_array = array_filter( explode( ',', $input['enforced_users'] ) );
856 foreach ( $enforced_users_array as $enforced_user ) {
857 $user = get_user_by( 'login', $enforced_user );
858 update_user_meta( $user->ID, 'wp_2fa_grace_period_expiry', $grace_expiry );
859 $user = get_user_by( 'login', $enforced_user );
860 self::send_2fa_enforced_email( $user->ID );
861 }
862 } else {
863 foreach ( $users as $user ) {
864 $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'] );
865 $is_user_excluded = WP2FA::is_user_excluded( $user, $output['excluded_users'], $output['excluded_roles'], $output['excluded_sites'] );
866 if ( $is_needed && ! $is_user_excluded ) {
867 update_user_meta( $user->ID, 'wp_2fa_grace_period_expiry', $grace_expiry );
868 self::send_2fa_enforced_email( $user->ID );
869 }
870 }
871 }
872 }
873
874 return $output;
875 }
876
877 /**
878 * Hide settings menu item
879 */
880 public function hide_settings() {
881 $user = wp_get_current_user();
882
883 // Check we have a user before doing anything else.
884 if ( is_a( $user, '\WP_User' ) ) {
885 $user_id = (int) $user->ID;
886 if ( ! empty( WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' ) ) ) {
887 $main_user = (int) WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' );
888 } else {
889 $main_user = '';
890 }
891 if ( ! empty( WP2FA::get_wp2fa_setting( 'limit_access' ) ) && $user->ID !== $main_user ) {
892 // Remove admin menu item.
893 remove_submenu_page( 'options-general.php', 'wp-2fa-settings' );
894 }
895 }
896 }
897
898 /**
899 * Add unlock user link to user actions.
900 *
901 * @param array $links Default row content.
902 */
903 public function add_plugin_action_links( $links ) {
904
905 if ( WP2FA::is_this_multisite() ) {
906 $url = network_admin_url( '/settings.php?page=wp-2fa-settings' );
907 } else {
908 $url = admin_url( '/options-general.php?page=wp-2fa-settings' );
909 }
910
911 $links = array_merge(
912 array(
913 '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Configure 2FA Settings', 'wp-2fa' ) . '</a>',
914 ),
915 $links
916 );
917
918 return $links;
919
920 }
921
922 /**
923 * User unlocked notice.
924 */
925 public function user_unlocked_notice() {
926 ?>
927 <div class="notice notice-success is-dismissible">
928 <p><?php esc_html_e( 'User account successfully unlocked. User can login again.', 'wp-2fa' ); ?></p>
929 <button type="button" class="notice-dismiss">
930 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
931 </button>
932 </div>
933 <?php
934 }
935
936 /**
937 * User deleted 2FA settings notification
938 */
939 public function user_deleted_2fa_notice() {
940 ?>
941 <div class="notice notice-success is-dismissible">
942 <p><?php esc_html_e( 'Your 2FA settings have been removed.', 'wp-2fa' ); ?></p>
943 <button type="button" class="notice-dismiss">
944 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
945 </button>
946 </div>
947 <?php
948 }
949
950 /**
951 * Admin deleted user 2FA settings notification
952 */
953 public function admin_deleted_2fa_notice() {
954 ?>
955 <div class="notice notice-success is-dismissible">
956 <p><?php esc_html_e( 'User 2FA settings have been removed.', 'wp-2fa' ); ?></p>
957 <button type="button" class="notice-dismiss">
958 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
959 </button>
960 </div>
961 <?php
962 }
963
964 /**
965 * Semd email to let user know they need to enabled 2FA
966 *
967 * @param int $user_id User ID.
968 */
969 public static function send_2fa_enforced_email( $user_id ) {
970 $user_id = (int) $user_id;
971 // Grab user data.
972 $user = get_userdata( $user_id );
973
974 // Check if user has any enabled 2FA methods before sending.
975 $enabled_methods = get_user_meta( $user->ID, 'wp_2fa_enabled_methods', true );
976 if ( ! empty( $enabled_methods ) ) {
977 return false;
978 }
979
980 // Grab user email.
981 $email = $user->user_email;
982
983 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'enforced_email_subject' ), $user_id ) );
984 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'enforced_email_body' ), $user_id ) );
985
986 $headers = 'Content-type: text/html;charset=utf-8' . "\r\n";
987
988 if ( 'use-custom-email' === WP2FA::get_wp2fa_email_templates( 'email_from_setting' ) ) {
989 $headers .= "From: ". WP2FA::get_wp2fa_email_templates( 'custom_from_display_name' ) ." <". WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' ) .">" . "\r\n";
990 }
991
992 $mail = wp_mail( $user->user_email, $subject, $message, $headers );
993 }
994
995 public function update_wp2fa_network_options() {
996 check_admin_referer( 'wp_2fa_settings-options' );
997
998 if ( isset( $_POST['wp_2fa_settings'] ) ) {
999 $options = $this->validate_and_sanitize( wp_unslash( $_POST['wp_2fa_settings'] ) );
1000 $update_options = update_network_option( null, 'wp_2fa_settings', $options );
1001 }
1002
1003 // redirect back to our options page.
1004 wp_safe_redirect(
1005 add_query_arg(
1006 array(
1007 'page' => 'wp-2fa-settings',
1008 'wp_2fa_network_settings_updated' => 'true',
1009 ),
1010 network_admin_url( 'settings.php' )
1011 )
1012 );
1013 exit;
1014 }
1015
1016 /**
1017 * Handle saving email options to the network main site options.
1018 */
1019 public function update_wp2fa_network_email_options() {
1020 if ( isset( $_POST['email_from_setting'] ) ) {
1021 $options = $this->validate_and_sanitize_email( wp_unslash( $_POST ) );
1022
1023 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'] ) ) {
1024 // redirect back to our options page.
1025 wp_safe_redirect(
1026 add_query_arg(
1027 array(
1028 'page' => 'wp-2fa-settings',
1029 'wp_2fa_network_settings_updated' => 'false',
1030 'tab' => 'email-settings'
1031 ),
1032 network_admin_url( 'settings.php' )
1033 )
1034 );
1035 exit;
1036 }
1037
1038 $update_options = update_network_option( null, 'wp_2fa_email_settings', $options );
1039 }
1040
1041 // redirect back to our options page.
1042 wp_safe_redirect(
1043 add_query_arg(
1044 array(
1045 'page' => 'wp-2fa-settings',
1046 'wp_2fa_network_settings_updated' => 'true',
1047 'tab' => 'email-settings'
1048 ),
1049 network_admin_url( 'settings.php' )
1050 )
1051 );
1052 exit;
1053 }
1054
1055 /**
1056 * These are used instead of add_settings_error which in a network site. Used to show if settings have been updated or failed.
1057 */
1058 public function settings_saved_network_admin_notice() {
1059 if ( isset( $_GET['wp_2fa_network_settings_updated'] ) && $_GET['wp_2fa_network_settings_updated'] == 'true' ): ?>
1060 <div class="notice notice-success is-dismissible">
1061 <p><?php esc_html_e( '2FA Settings Updated', 'wp-2fa' ); ?></p>
1062 <button type="button" class="notice-dismiss">
1063 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
1064 </button>
1065 </div>
1066 <?php
1067 endif;
1068 if ( isset( $_GET['wp_2fa_network_settings_updated'] ) && $_GET['wp_2fa_network_settings_updated'] == 'false' ): ?>
1069 <div class="notice notice-error is-dismissible">
1070 <p><?php esc_html_e( 'Please ensure both custom email address and display name are provided.', 'wp-2fa' ); ?></p>
1071 <button type="button" class="notice-dismiss">
1072 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
1073 </button>
1074 </div>
1075 <?php
1076 endif;
1077 }
1078
1079 /**
1080 * Email settings
1081 */
1082 private function email_from_settings() {
1083 ?>
1084 <h3><?php esc_html_e( 'Which email address should the plugin use as a from address?', 'wp-2fa' ); ?></h3>
1085 <p class="description">
1086 <?php esc_html_e( 'Use these settings to customize the "from" name and email address for all correspondence sent from our plugin.', 'wp-2fa' ); ?>
1087 </p>
1088 <table class="form-table">
1089 <tbody>
1090 <tr>
1091 <th><label for="2fa-method"><?php esc_html_e( 'From email & name', 'wp-2fa' ); ?></label>
1092 </th>
1093 <td>
1094 <fieldset class="contains-hidden-inputs">
1095 <label for="use-defaults">
1096 <input type="radio" name="email_from_setting" id="use-defaults" value="use-defaults"
1097 <?php checked( WP2FA::get_wp2fa_email_templates( 'email_from_setting' ), 'use-defaults' ); ?>
1098 >
1099 <span><?php esc_html_e( 'Use the email address from the WordPress general settings.', 'wp-2fa' ); ?></span>
1100 </label>
1101
1102 <br/>
1103 <label for="use-custom-email">
1104 <input type="radio" name="email_from_setting" id="use-custom-email" value="use-custom-email"
1105 <?php checked( WP2FA::get_wp2fa_email_templates( 'email_from_setting' ), 'use-custom-email' ); ?>
1106 data-unhide-when-checked=".custom-from-inputs">
1107 <span><?php esc_html_e( 'Use another email address', 'wp-2fa' ); ?></span>
1108 </label>
1109 <fieldset class="hidden custom-from-inputs">
1110 <br/>
1111 <span><?php esc_html_e( 'Email Address:', 'wp-2fa' ); ?></span> <input type="email" id="custom_from_email_address" name="custom_from_email_address" value="<?php echo WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' ); ?>"><br><br>
1112 <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' ); ?>">
1113 </fieldset>
1114
1115 </fieldset>
1116 </td>
1117 </tr>
1118 </tbody>
1119 </table>
1120
1121 <br>
1122 <hr>
1123
1124 <?php
1125 }
1126
1127 /**
1128 * Email settings
1129 */
1130 private function email_settings() {
1131 ?>
1132 <h1><?php esc_html_e( 'Email Templates', 'wp-2fa' ); ?></h1>
1133 <h3><?php esc_html_e( 'Enforced 2FA email', 'wp-2fa' ); ?></h3>
1134 <p class="description">
1135 <?php esc_html_e( 'This is the email sent to applicable users when you enforce 2fa.', 'wp-2fa' ); ?>
1136 </p>
1137 <table class="form-table">
1138 <tbody>
1139 <tr>
1140 <th><label for="2fa-method"><?php esc_html_e( 'Email subject', 'wp-2fa' ); ?></label>
1141 </th>
1142 <td>
1143 <fieldset>
1144 <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' ) ) ?>">
1145 </fieldset>
1146 </td>
1147 </tr>
1148 <tr>
1149 <th><label for="2fa-method"><?php esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
1150 </br>
1151 <label for="2fa-method" style="font-weight: 400;"><?php esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
1152 </br></br>
1153 <span style="font-weight: 400;">
1154 {site_url}</br>
1155 {site_name}</br>
1156 {grace_period}</br>
1157 {user_login_name}</br>
1158 {login_code}
1159 </span>
1160 </th>
1161 <td>
1162 <fieldset>
1163 <?php
1164 $message = WP2FA::get_wp2fa_email_templates( 'enforced_email_body' );
1165 $content = $message;
1166 $editor_id = 'enforced_email_body';
1167 $settings = array(
1168 'media_buttons' => false,
1169 'editor_height' => 200,
1170 );
1171 wp_editor( $content, $editor_id, $settings );
1172 ?>
1173 </fieldset>
1174 </td>
1175 </tr>
1176 </tbody>
1177 </table>
1178
1179 <br>
1180 <hr>
1181
1182 <h3><?php esc_html_e( 'Login code email', 'wp-2fa' ); ?></h3>
1183 <p class="description">
1184 <?php esc_html_e( 'This is the email sent to a user when a login code is required.', 'wp-2fa' ); ?>
1185 </p>
1186 <table class="form-table">
1187 <tbody>
1188 <tr>
1189 <th><label for="2fa-method"><?php esc_html_e( 'Email subject', 'wp-2fa' ); ?></label>
1190 </th>
1191 <td>
1192 <fieldset>
1193 <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' ) ) ?>">
1194 </fieldset>
1195 </td>
1196 </tr>
1197 <tr>
1198 <th><label for="2fa-method"><?php esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
1199 </br>
1200 <label for="2fa-method" style="font-weight: 400;"><?php esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
1201 </br></br>
1202 <span style="font-weight: 400;">
1203 {site_url}</br>
1204 {site_name}</br>
1205 {grace_period}</br>
1206 {user_login_name}</br>
1207 {login_code}
1208 </span>
1209 </th>
1210 <td>
1211 <fieldset>
1212 <?php
1213 $message = WP2FA::get_wp2fa_email_templates( 'login_code_email_body' );
1214 $content = $message;
1215 $editor_id = 'login_code_email_body';
1216 $settings = array(
1217 'media_buttons' => false,
1218 'editor_height' => 200,
1219 );
1220 wp_editor( $content, $editor_id, $settings );
1221 ?>
1222 </fieldset>
1223 </td>
1224 </tr>
1225 </tbody>
1226 </table>
1227
1228 <br>
1229 <hr>
1230
1231 <h3><?php esc_html_e( 'User account locked email', 'wp-2fa' ); ?></h3>
1232 <p class="description">
1233 <?php esc_html_e( 'This is the email sent to a user upon grace period expiry.', 'wp-2fa' ); ?>
1234 </p>
1235 <table class="form-table">
1236 <tbody>
1237 <tr>
1238 <th><label for="2fa-method"><?php esc_html_e( 'Email subject', 'wp-2fa' ); ?></label>
1239 </th>
1240 <td>
1241 <fieldset>
1242 <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' ) ) ?>">
1243 </fieldset>
1244 </td>
1245 </tr>
1246 <tr>
1247 <th><label for="2fa-method"><?php esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
1248 </br>
1249 <label for="2fa-method" style="font-weight: 400;"><?php esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
1250 </br></br>
1251 <span style="font-weight: 400;">
1252 {site_url}</br>
1253 {site_name}</br>
1254 {grace_period}</br>
1255 {user_login_name}</br>
1256 {login_code}
1257 </span>
1258 </th>
1259 <td>
1260 <fieldset>
1261 <?php
1262 $message = WP2FA::get_wp2fa_email_templates( 'user_account_locked_email_body' );
1263 $content = $message;
1264 $editor_id = 'user_account_locked_email_body';
1265 $settings = array(
1266 'media_buttons' => false,
1267 'editor_height' => 200,
1268 );
1269 wp_editor( $content, $editor_id, $settings );
1270 ?>
1271 </fieldset>
1272 </td>
1273 </tr>
1274 </tbody>
1275 </table>
1276
1277 <br>
1278 <hr>
1279
1280 <h3><?php esc_html_e( 'User account unlocked email', 'wp-2fa' ); ?></h3>
1281 <p class="description">
1282 <?php esc_html_e( 'This is the email sent to a user when the user\'s account has been unlocked.', 'wp-2fa' ); ?>
1283 </p>
1284 <table class="form-table">
1285 <tbody>
1286 <tr>
1287 <th><label for="2fa-method"><?php esc_html_e( 'Email subject', 'wp-2fa' ); ?></label>
1288 </th>
1289 <td>
1290 <fieldset>
1291 <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' ) ) ?>">
1292 </fieldset>
1293 </td>
1294 </tr>
1295 <tr>
1296 <th><label for="2fa-method"><?php esc_html_e( 'Email body', 'wp-2fa' ); ?></label>
1297 </br>
1298 <label for="2fa-method" style="font-weight: 400;"><?php esc_html_e( 'Available template tags:', 'wp-2fa' ); ?></label>
1299 </br></br>
1300 <span style="font-weight: 400;">
1301 {site_url}</br>
1302 {site_name}</br>
1303 {grace_period}</br>
1304 {user_login_name}</br>
1305 {login_code}
1306 </span>
1307 </th>
1308 <td>
1309 <fieldset>
1310 <?php
1311 $message = WP2FA::get_wp2fa_email_templates( 'user_account_unlocked_email_body' );
1312 $content = $message;
1313 $editor_id = 'user_account_unlocked_email_body';
1314 $settings = array(
1315 'media_buttons' => false,
1316 'editor_height' => 200,
1317 );
1318 wp_editor( $content, $editor_id, $settings );
1319 ?>
1320 </fieldset>
1321 </td>
1322 </tr>
1323 </tbody>
1324 </table>
1325 <?php
1326 }
1327
1328 /**
1329 * Validate email templates before saving
1330 *
1331 * @param array $input The settings array.
1332 */
1333 public function validate_and_sanitize_email( $input ) {
1334
1335 // Bail if user doesnt have permissions to be here.
1336 if ( ! current_user_can( 'manage_options' ) ) {
1337 return;
1338 }
1339
1340 if ( empty( $_POST ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'wp_2fa_email_settings-options' ) ) {
1341 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
1342 }
1343
1344 if ( isset( $_POST['email_from_setting'] ) && 'use-defaults' === $_POST['email_from_setting'] || isset( $_POST['email_from_setting'] ) && 'use-custom-email' === $_POST['email_from_setting'] ) {
1345 $output['email_from_setting'] = sanitize_text_field( wp_unslash( $_POST['email_from_setting'] ) );
1346 }
1347
1348 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'] ) ) {
1349 add_settings_error(
1350 'wp_2fa_settings',
1351 esc_attr( 'settings_error' ),
1352 esc_html__( 'Please provide an email address', 'wp-2fa' ),
1353 'error'
1354 );
1355 $output['custom_from_email_address'] = '';
1356 }
1357
1358 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'] ) ) {
1359 add_settings_error(
1360 'wp_2fa_settings',
1361 esc_attr( 'settings_error' ),
1362 esc_html__( 'Please provide a display name.', 'wp-2fa' ),
1363 'error'
1364 );
1365 $output['custom_from_email_address'] = '';
1366 }
1367
1368
1369 if ( isset( $_POST['custom_from_email_address'] ) && ! empty( $_POST['custom_from_email_address'] ) && is_email( $_POST['custom_from_email_address'] ) ) {
1370 $output['custom_from_email_address'] = sanitize_email( wp_unslash( $_POST['custom_from_email_address'] ) );
1371 }
1372
1373 if ( isset( $_POST['custom_from_display_name'] ) && ! empty( $_POST['custom_from_display_name'] ) ) {
1374 $output['custom_from_display_name'] = sanitize_text_field( wp_unslash( $_POST['custom_from_display_name'] ) );
1375 }
1376
1377 if ( isset( $_POST['enforced_email_subject'] ) ) {
1378 $output['enforced_email_subject'] = wp_kses_post( wp_unslash( $_POST['enforced_email_subject'] ) );
1379 }
1380
1381 if ( isset( $_POST['enforced_email_body'] ) ) {
1382 $output['enforced_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['enforced_email_body'] ) ) );
1383 }
1384
1385 if ( isset( $_POST['login_code_email_subject'] ) ) {
1386 $output['login_code_email_subject'] = wp_kses_post( wp_unslash( $_POST['login_code_email_subject'] ) );
1387 }
1388
1389 if ( isset( $_POST['login_code_email_body'] ) ) {
1390 $output['login_code_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['login_code_email_body'] ) ) );
1391 }
1392
1393 if ( isset( $_POST['user_account_locked_email_subject'] ) ) {
1394 $output['user_account_locked_email_subject'] = wp_kses_post( wp_unslash( $_POST['user_account_locked_email_subject'] ) );
1395 }
1396
1397 if ( isset( $_POST['user_account_locked_email_body'] ) ) {
1398 $output['user_account_locked_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['user_account_locked_email_body'] ) ) );
1399 }
1400
1401 if ( isset( $_POST['user_account_unlocked_email_subject'] ) ) {
1402 $output['user_account_unlocked_email_subject'] = wp_kses_post( wp_unslash( $_POST['user_account_unlocked_email_subject'] ) );
1403 }
1404
1405 if ( isset( $_POST['user_account_unlocked_email_body'] ) ) {
1406 $output['user_account_unlocked_email_body'] = wpautop( wp_kses_post( wp_unslash( $_POST['user_account_unlocked_email_body'] ) ) );
1407 }
1408
1409 return $output;
1410 }
1411 }
1412