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