PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.4.0
WP 2FA – Two-factor authentication for WordPress v2.4.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 / class-settings-page.php
wp-2fa / includes / classes / Admin Last commit date
Controllers 3 years ago Helpers 3 years ago SettingsPages 3 years ago Views 3 years ago class-help-contact-us.php 3 years ago class-premium-features.php 3 years ago class-settings-page.php 3 years ago class-settingspage.php 3 years ago class-setup-wizard.php 3 years ago class-user-listing.php 3 years ago class-user-notices.php 3 years ago class-user-profile.php 3 years ago class-user-registered.php 3 years ago class-user.php 3 years ago index.php 5 years ago
class-settings-page.php
697 lines
1 <?php
2 /**
3 * Settings rendering class.
4 *
5 * @package wp2fa
6 * @subpackage settings
7 * @copyright 2023 WP White Security
8 * @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
9 * @link https://wordpress.org/plugins/wp-2fa/
10 */
11
12 namespace WP2FA\Admin;
13
14 use \WP2FA\WP2FA as WP2FA;
15 use WP2FA\Utils\User_Utils;
16 use WP2FA\Utils\Settings_Utils;
17 use WP2FA\Admin\Views\Settings_Page_Render;
18 use WP2FA\Admin\SettingsPages\{
19 Settings_Page_Policies,
20 Settings_Page_General,
21 Settings_Page_White_Label,
22 Settings_Page_Email
23 };
24 use WP2FA\Admin\Helpers\WP_Helper;
25 use WP2FA\Admin\Helpers\User_Helper;
26 use WP2FA\Admin\Controllers\Settings;
27
28 /**
29 * Class for handling settings
30 */
31 if ( ! class_exists( '\WP2FA\Admin\Settings_Page' ) ) {
32 /**
33 * Class for handling settings
34 */
35 class Settings_Page {
36
37 const TOP_MENU_SLUG = 'wp-2fa-policies';
38
39 /**
40 * Holds the status of the backup codes functionality
41 *
42 * @var bool[]
43 */
44 private static $backup_codes_enabled = array();
45
46 /**
47 * Create admin menu entry and settings page
48 */
49 public static function create_settings_admin_menu() {
50 // Create admin menu item.
51 add_menu_page(
52 esc_html__( 'WP 2FA', 'wp-2fa' ),
53 esc_html__( 'WP 2FA', 'wp-2fa' ),
54 'manage_options',
55 self::TOP_MENU_SLUG,
56 null,
57 'data:image/svg+xml;base64,' . base64_encode( file_get_contents( WP_2FA_PATH . 'dist/images/wp-2fa-white-icon20x28.svg' ) ), // phpcs:ignore
58 81
59 );
60
61 $settings_policies = new Settings_Page_Policies();
62 $settings_white_label = new Settings_Page_White_Label();
63 $settings_render = new Settings_Page_Render();
64
65 add_submenu_page(
66 self::TOP_MENU_SLUG,
67 esc_html__( '2FA Policies', 'wp-2fa' ),
68 esc_html__( '2FA Policies', 'wp-2fa' ),
69 'manage_options',
70 self::TOP_MENU_SLUG,
71 array( $settings_policies, 'render' ),
72 1
73 );
74
75 add_submenu_page(
76 self::TOP_MENU_SLUG,
77 esc_html__( 'WP 2FA Settings', 'wp-2fa' ),
78 esc_html__( 'Settings', 'wp-2fa' ),
79 'manage_options',
80 'wp-2fa-settings',
81 array( $settings_render, 'render' ),
82 2
83 );
84
85 // Register our policy settings.
86 register_setting(
87 WP_2FA_POLICY_SETTINGS_NAME,
88 WP_2FA_POLICY_SETTINGS_NAME,
89 array( $settings_policies, 'validate_and_sanitize' )
90 );
91
92 // Register our white label settings.
93 register_setting(
94 WP_2FA_WHITE_LABEL_SETTINGS_NAME,
95 WP_2FA_WHITE_LABEL_SETTINGS_NAME,
96 array( $settings_white_label, 'validate_and_sanitize' )
97 );
98
99 // Register our settings page.
100 register_setting(
101 WP_2FA_SETTINGS_NAME,
102 WP_2FA_SETTINGS_NAME,
103 array( \WP2FA\Admin\SettingsPages\Settings_Page_General::class, 'validate_and_sanitize' )
104 );
105
106 register_setting(
107 WP_2FA_EMAIL_SETTINGS_NAME,
108 WP_2FA_EMAIL_SETTINGS_NAME,
109 array( \WP2FA\Admin\SettingsPages\Settings_Page_Email::class, 'validate_and_sanitize' )
110 );
111
112 /**
113 * Fires after the main menu settings are registered.
114 *
115 * @param string - The menu slug.
116 * @param bool - Is that multisite install or not.
117 *
118 * @since 2.0.0
119 */
120 do_action( WP_2FA_PREFIX . 'after_admin_menu_created', self::TOP_MENU_SLUG, false );
121 }
122
123 /**
124 * Create admin menu entry and settings page
125 */
126 public static function create_settings_admin_menu_multisite() {
127 // Create admin menu item.
128 add_menu_page(
129 esc_html__( 'WP 2FA Settings', 'wp-2fa' ),
130 esc_html__( 'WP 2FA', 'wp-2fa' ),
131 'manage_options',
132 self::TOP_MENU_SLUG,
133 null,
134 'data:image/svg+xml;base64,' . base64_encode( file_get_contents( WP_2FA_PATH . 'dist/images/wp-2fa-white-icon20x28.svg' ) ), // phpcs:ignore
135 81
136 );
137
138 $settings_policies = new Settings_Page_Policies();
139 add_submenu_page(
140 self::TOP_MENU_SLUG,
141 esc_html__( '2FA Policies', 'wp-2fa' ),
142 esc_html__( '2FA Policies', 'wp-2fa' ),
143 'manage_options',
144 self::TOP_MENU_SLUG,
145 array( $settings_policies, 'render' ),
146 1
147 );
148
149 $settings_render = new Settings_Page_Render();
150 add_submenu_page(
151 self::TOP_MENU_SLUG,
152 esc_html__( 'WP 2FA Settings', 'wp-2fa' ),
153 esc_html__( 'Settings', 'wp-2fa' ),
154 'manage_options',
155 'wp-2fa-settings',
156 array( $settings_render, 'render' ),
157 2
158 );
159
160 /**
161 * Fires after the main menu settings are registered.
162 *
163 * @param string - The menu slug.
164 * @param bool - Is that multisite install or not.
165 *
166 * @since 2.0.0
167 */
168 do_action( WP_2FA_PREFIX . 'after_admin_menu_created', self::TOP_MENU_SLUG, true );
169 }
170
171 /**
172 * Get all users
173 *
174 * @SuppressWarnings(PHPMD.ExitExpression)
175 */
176 public static function get_all_users() {
177 // Die if user does not have permission to view.
178 if ( ! current_user_can( 'manage_options' ) ) {
179 die( 'Access Denied.' );
180 }
181 // Filter $_GET array for security.
182 $get_array = filter_input_array( INPUT_GET );
183
184 // Die if nonce verification failed.
185 if ( ! wp_verify_nonce( sanitize_text_field( $get_array['wp_2fa_nonce'] ), 'wp-2fa-settings-nonce' ) ) {
186 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
187 }
188
189 $users_args = array(
190 'fields' => array( 'ID', 'user_login' ),
191 );
192 if ( WP_Helper::is_multisite() ) {
193 $users_args['blog_id'] = 0;
194 }
195 $users_data = User_Utils::get_all_user_ids_and_login_names( 'query', $users_args );
196
197 // Create final array which we will fill in below.
198 $users = array();
199
200 foreach ( $users_data as $user ) {
201 if ( strpos( $user['user_login'], $get_array['term'] ) !== false ) {
202 array_push(
203 $users,
204 array(
205 'value' => $user['user_login'],
206 'label' => $user['user_login'],
207 )
208 );
209 }
210 }
211
212 echo wp_json_encode( $users );
213 exit;
214 }
215
216 /**
217 * Get all network sites
218 *
219 * @SuppressWarnings(PHPMD.ExitExpression)
220 */
221 public static function get_all_network_sites() {
222 // Die if user does not have permission to view.
223 if ( ! current_user_can( 'manage_options' ) ) {
224 die( 'Access Denied.' );
225 }
226 // Filter $_GET array for security.
227 $get_array = filter_input_array( INPUT_GET );
228 // Die if nonce verification failed.
229 if ( ! wp_verify_nonce( sanitize_text_field( $get_array['wp_2fa_nonce'] ), 'wp-2fa-settings-nonce' ) ) {
230 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
231 }
232 // Fetch sites.
233 $sites_found = array();
234
235 foreach ( get_sites() as $site ) {
236 $subsite_id = get_object_vars( $site )['blog_id'];
237 $subsite_name = get_blog_details( $subsite_id )->blogname;
238 $site_details = '';
239 $site_details[ $subsite_id ] = $subsite_name;
240 if ( false !== stripos( $subsite_name, $get_array['term'] ) ) {
241 array_push(
242 $sites_found,
243 array(
244 'label' => $subsite_id,
245 'value' => $subsite_name,
246 )
247 );
248 }
249 }
250 echo wp_json_encode( $sites_found );
251 exit;
252 }
253
254 /**
255 * Unlock users accounts if they have overrun grace period
256 *
257 * @param int $user_id User ID.
258 *
259 * @SuppressWarnings(PHPMD.ExitExpression)
260 */
261 public static function unlock_account( $user_id ) {
262 // Die if user does not have permission to view.
263 if ( ! current_user_can( 'manage_options' ) ) {
264 die( 'Access Denied.' );
265 }
266
267 $grace_period = WP2FA::get_wp2fa_setting( 'grace-period' );
268 $grace_period_denominator = WP2FA::get_wp2fa_setting( 'grace-period-denominator' );
269 $create_a_string = $grace_period . ' ' . $grace_period_denominator;
270 // Turn that string into a time.
271 $grace_expiry = strtotime( $create_a_string );
272
273 // Filter $_GET array for security.
274 $get_array = filter_input_array( INPUT_GET );
275 $nonce = sanitize_text_field( $get_array['wp_2fa_nonce'] );
276
277 // Die if nonce verification failed.
278 if ( ! wp_verify_nonce( $nonce, 'wp-2fa-unlock-account-nonce' ) ) {
279 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
280 }
281
282 if ( isset( $get_array['user_id'] ) ) {
283 global $wpdb;
284 $wpdb->query( // phpcs:ignore
285 $wpdb->prepare(
286 "
287 DELETE FROM $wpdb->usermeta
288 WHERE user_id = %d
289 AND meta_key IN ( %s, %s )
290 ",
291 array(
292 intval( $get_array['user_id'] ),
293 User_Helper::USER_GRACE_KEY,
294 WP_2FA_PREFIX . 'locked_account_notification',
295 )
296 )
297 );
298 User_Helper::set_user_expiry_date( $grace_expiry, intval( $get_array['user_id'] ) );
299 self::send_account_unlocked_email( intval( $get_array['user_id'] ) );
300 add_action( 'admin_notices', array( __CLASS__, 'user_unlocked_notice' ) );
301 }
302 }
303
304 /**
305 * Remove user 2fa config
306 *
307 * @param int $user_id User ID.
308 *
309 * @SuppressWarnings(PHPMD.ExitExpression)
310 */
311 public static function remove_user_2fa( $user_id ) {
312 // Filter $_GET array for security.
313 $get_array = filter_input_array( INPUT_GET );
314 $nonce = sanitize_text_field( $get_array['wp_2fa_nonce'] );
315
316 if ( ! wp_verify_nonce( $nonce, 'wp-2fa-remove-user-2fa-nonce' ) ) {
317 die( esc_html__( 'Nonce verification failed.', 'wp-2fa' ) );
318 }
319
320 if ( isset( $get_array['user_id'] ) ) {
321 $user_id = intval( $get_array['user_id'] );
322
323 if ( ! current_user_can( 'manage_options' ) && get_current_user_id() !== $user_id ) {
324 return;
325 }
326
327 User_Helper::remove_2fa_for_user( $user_id );
328
329 if ( isset( $get_array['admin_reset'] ) ) {
330 add_action( 'admin_notices', array( __CLASS__, 'admin_deleted_2fa_notice' ) );
331 } else {
332 add_action( 'admin_notices', array( __CLASS__, 'user_deleted_2fa_notice' ) );
333 }
334 }
335 }
336
337 /**
338 * Send account unlocked notification via email.
339 *
340 * @param int $user_id user ID.
341 *
342 * @return boolean
343 */
344 public static function send_account_unlocked_email( $user_id ) {
345 // Bail if the user has not enabled this email.
346 if ( 'enable_account_unlocked_email' !== WP2FA::get_wp2fa_email_templates( 'send_account_unlocked_email' ) ) {
347 return false;
348 }
349
350 // Grab user data.
351 $user = get_userdata( $user_id );
352 // Grab user email.
353 $email = $user->user_email;
354 // Setup the email contents.
355 $subject = wp_strip_all_tags( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_account_unlocked_email_subject' ) ) );
356 $message = wpautop( WP2FA::replace_email_strings( WP2FA::get_wp2fa_email_templates( 'user_account_unlocked_email_body' ), $user_id ) );
357
358 return self::send_email( $email, $subject, $message );
359 }
360
361 /**
362 * Hide settings menu item
363 */
364 public static function hide_settings() {
365 $user = wp_get_current_user();
366
367 // Check we have a user before doing anything else.
368 if ( is_a( $user, '\WP_User' ) ) {
369 if ( ! empty( WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' ) ) ) {
370 $main_user = (int) WP2FA::get_wp2fa_setting( '2fa_settings_last_updated_by' );
371 } else {
372 $main_user = get_current_user_id();
373 }
374 if ( ! empty( WP2FA::get_wp2fa_general_setting( 'limit_access' ) ) && $user->ID !== $main_user ) {
375 // Remove admin menu item.
376 remove_submenu_page( 'options-general.php', self::TOP_MENU_SLUG );
377 }
378 }
379 }
380
381 /**
382 * Add unlock user link to user actions.
383 *
384 * @param array $links Default row content.
385 *
386 * @return array
387 * @throws \Freemius_Exception - freemius exception.
388 */
389 public static function add_plugin_action_links( $links ) {
390 // add link to the external free trial page in free version and also in premium version if license is not active.
391 if ( ! function_exists( 'wp2fa_freemius' ) || ! wp2fa_freemius()->has_active_valid_license() ) {
392 $trial_link = 'https://wp2fa.io/get-wp-2fa-premium-trial/?utm_source=plugin&utm_medium=referral&utm_campaign=WP2FA';
393 $links = array_merge(
394 array(
395 '<a style="font-weight:bold" href="' . $trial_link . '" target="_blank">' . __( 'Free 14-day Premium Trial', 'wp-2fa' ) . '</a>',
396 ),
397 $links
398 );
399 }
400
401 // add link to the plugin settings page.
402 $url = Settings::get_settings_page_link();
403 $links = array_merge(
404 array(
405 '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Configure 2FA Settings', 'wp-2fa' ) . '</a>',
406 ),
407 $links
408 );
409
410 return $links;
411 }
412
413 /**
414 * User unlocked notice.
415 */
416 public static function user_unlocked_notice() {
417 ?>
418 <div class="notice notice-success is-dismissible">
419 <p><?php esc_html_e( 'User account successfully unlocked. User can login again.', 'wp-2fa' ); ?></p>
420 <button type="button" class="notice-dismiss">
421 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
422 </button>
423 </div>
424 <?php
425 }
426
427 /**
428 * User deleted 2FA settings notification
429 */
430 public static function user_deleted_2fa_notice() {
431 ?>
432 <div class="notice notice-success is-dismissible">
433 <p><?php esc_html_e( 'Your 2FA settings have been removed.', 'wp-2fa' ); ?></p>
434 <button type="button" class="notice-dismiss">
435 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
436 </button>
437 </div>
438 <?php
439 }
440
441 /**
442 * Admin deleted user 2FA settings notification
443 */
444 public static function admin_deleted_2fa_notice() {
445 ?>
446 <div class="notice notice-success is-dismissible">
447 <p><?php esc_html_e( 'User 2FA settings have been removed.', 'wp-2fa' ); ?></p>
448 <button type="button" class="notice-dismiss">
449 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
450 </button>
451 </div>
452 <?php
453 }
454
455 /**
456 * Updates options for multisite
457 *
458 * @return void
459 *
460 * @since 2.0.0
461 */
462 public static function update_wp2fa_network_options() {
463
464 $settings_policies = new Settings_Page_Policies();
465
466 $settings_policies->update_wp2fa_network_options();
467
468 Settings_Page_General::update_wp2fa_network_options();
469
470 $settings_white_label = new Settings_Page_White_Label();
471
472 $settings_white_label->update_wp2fa_network_options();
473
474 /**
475 * Gives the ability for extensions to set their settings in the plugin.
476 *
477 * @since 2.2.0
478 */
479 do_action( WP_2FA_PREFIX . 'update_network_settings' );
480 }
481
482 /**
483 * Handle saving email options to the network main site options.
484 */
485 public static function update_wp2fa_network_email_options() {
486 Settings_Page_Email::update_wp2fa_network_options();
487 }
488
489 /**
490 * These are used instead of add_settings_error which in a network site. Used to show if settings have been updated or failed.
491 */
492 public static function settings_saved_network_admin_notice() {
493 if ( isset( $_GET['wp_2fa_network_settings_updated'] ) && 'true' === $_GET['wp_2fa_network_settings_updated'] ) { // phpcs:ignore
494 ?>
495 <div class="notice notice-success is-dismissible">
496 <p><?php esc_html_e( '2FA Settings Updated', 'wp-2fa' ); ?></p>
497 <button type="button" class="notice-dismiss">
498 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
499 </button>
500 </div>
501 <?php
502 }
503 if ( isset( $_GET['wp_2fa_network_settings_updated'] ) && 'false' === $_GET['wp_2fa_network_settings_updated'] ) { // phpcs:ignore
504 ?>
505 <div class="notice notice-error is-dismissible">
506 <?php
507 if ( isset( $_GET['wp_2fa_network_settings_custom_error_message'] ) ) { // phpcs:ignore
508 ?>
509 <p><?php echo \wp_unslash( $_GET['wp_2fa_network_settings_custom_error_message'] ); // phpcs:ignore ?></p>
510 <button type="button" class="notice-dismiss">
511 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
512 </button>
513 <?php
514 } else {
515 ?>
516 <p><?php esc_html_e( 'Please ensure both custom email address and display name are provided.', 'wp-2fa' ); ?></p>
517 <button type="button" class="notice-dismiss">
518 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
519 </button>
520 <?php
521 }
522 ?>
523 </div>
524 <?php
525 }
526 if ( isset( $_GET['wp_2fa_network_settings_error'] ) ) { // phpcs:ignore
527 ?>
528 <div class="notice notice-error is-dismissible">
529 <p><?php echo \esc_attr( \esc_url_raw( \urldecode_deep( \wp_unslash( $_GET['wp_2fa_network_settings_error'] ) ) ) ); // phpcs:ignore ?></p>
530 <button type="button" class="notice-dismiss">
531 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
532 </button>
533 </div>
534 <?php
535 }
536 }
537
538 /**
539 * These are used instead of add_settings_error which in a network site. Used to show if settings have been updated or failed.
540 *
541 * @return void
542 *
543 * @since 2.0.0
544 */
545 public static function settings_saved_admin_notice() {
546 if ( isset( $_GET['settings-updated'] ) && 'true' === $_GET['settings-updated'] ) { // phpcs:ignore
547 $wp_settings_errors = get_settings_errors();
548
549 if ( count( $wp_settings_errors ) ) {
550 foreach ( $wp_settings_errors as $error ) {
551 ?>
552 <div class="notice notice-<?php echo \esc_attr( $error['type'] ); ?> is-dismissible">
553 <p><?php echo \esc_html( $error['message'] ); ?></p>
554 <button type="button" class="notice-dismiss">
555 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
556 </button>
557 </div>
558 <?php
559 }
560 } else {
561 ?>
562 <div class="notice notice-success is-dismissible">
563 <p><?php esc_html_e( '2FA Settings Updated', 'wp-2fa' ); ?></p>
564 <button type="button" class="notice-dismiss">
565 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
566 </button>
567 </div>
568 <?php
569 }
570 }
571 if ( isset( $_GET['settings-updated'] ) && 'false' === $_GET['settings-updated'] ) { // phpcs:ignore
572 ?>
573 <div class="notice notice-error is-dismissible">
574 <p><?php esc_html_e( 'Please ensure both custom email address and display name are provided.', 'wp-2fa' ); ?></p>
575 <button type="button" class="notice-dismiss">
576 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
577 </button>
578 </div>
579 <?php
580 }
581 if ( isset( $_GET['settings_error'] ) ) { // phpcs:ignore
582 ?>
583 <div class="notice notice-error is-dismissible">
584 <p><?php echo \esc_attr( \esc_url_raw( \urldecode_deep( \wp_unslash( $_GET['settings_error'] ) ) ) ); // phpcs:ignore ?></p>
585 <button type="button" class="notice-dismiss">
586 <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'wp-2fa' ); ?></span>
587 </button>
588 </div>
589 <?php
590 }
591 }
592
593 /**
594 * Add our custom state to our created page.
595 *
596 * @param array $post_states - array with the post states.
597 * @param WP_Post $post - the WP post.
598 *
599 * @return array
600 */
601 public static function add_display_post_states( $post_states, $post ) {
602 if ( ! empty( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) ) ) {
603 if ( WP2FA::get_wp2fa_setting( 'custom-user-page-id' ) === $post->ID ) {
604 $post_states['wp_2fa_page_for_user'] = __( 'WP 2FA User Page', 'wp-2fa' );
605 }
606 }
607
608 return $post_states;
609 }
610
611 /**
612 * Handles sending of an email. It sets necessary header such as content type and custom from email address and name.
613 *
614 * @param string $recipient_email Email address to send message to.
615 * @param string $subject Email subject.
616 * @param string $message Message contents.
617 *
618 * @return bool Whether the email contents were sent successfully.
619 */
620 public static function send_email( $recipient_email, $subject, $message ) {
621
622 // Specify our desired headers.
623 $headers = 'Content-type: text/html;charset=utf-8' . "\r\n";
624
625 if ( 'use-custom-email' === WP2FA::get_wp2fa_email_templates( 'email_from_setting' ) ) {
626 $headers .= 'From: ' . WP2FA::get_wp2fa_email_templates( 'custom_from_display_name' ) . ' <' . WP2FA::get_wp2fa_email_templates( 'custom_from_email_address' ) . '>' . "\r\n";
627 } else {
628 $headers .= 'From: ' . get_bloginfo( 'name' ) . ' <' . get_bloginfo( 'admin_email' ) . '>' . "\r\n";
629 }
630
631 // Fire our email.
632 return wp_mail( $recipient_email, $subject, $message, $headers );
633
634 }
635
636 /**
637 * Turns user roles data in any form and shape to an array of strings.
638 *
639 * @param mixed $value User role names (slugs) as raw value.
640 *
641 * @return string[] List of user role names (slugs).
642 */
643 public static function extract_roles_from_input( $value ) {
644 if ( is_array( $value ) ) {
645 return $value;
646 }
647
648 if ( is_string( $value ) && ! empty( $value ) ) {
649 return explode( ',', $value );
650 }
651
652 return array();
653 }
654
655 /**
656 * Determine if any BG processes are currently running.
657 *
658 * @return int|false Number of jobs.
659 */
660 public static function get_current_number_of_active_bg_processes() {
661 global $wpdb;
662
663 $bg_jobs = $wpdb->get_results( // phpcs:ignore
664 "SELECT option_value FROM $wpdb->options
665 WHERE option_name LIKE '%_2fa_bg_%'"
666 );
667
668 return count( $bg_jobs );
669 }
670
671 /**
672 * Checks if the backup codes option is enabled for the role
673 *
674 * @param string $role - The role name.
675 *
676 * @return bool
677 */
678 public static function are_backup_codes_enabled( $role = 'global' ) {
679
680 $role = ( is_null( $role ) || empty( $role ) ) ? 'global' : $role;
681
682 if ( ! isset( self::$backup_codes_enabled[ $role ] ) ) {
683 self::$backup_codes_enabled[ $role ] = false;
684
685 if ( 'global' === $role ) {
686 $setting_value = Settings::get_role_or_default_setting( 'backup_codes_enabled' );
687 } else {
688 $setting_value = Settings::get_role_or_default_setting( 'backup_codes_enabled', 'current', $role );
689 }
690 self::$backup_codes_enabled[ $role ] = Settings_Utils::string_to_bool( $setting_value );
691 }
692
693 return self::$backup_codes_enabled[ $role ];
694 }
695 }
696 }
697