PluginProbe ʕ •ᴥ•ʔ
Limit Login Attempts Security – Login Security, 2FA, Firewall, Brute Force Prevention / 3.2.4
Limit Login Attempts Security – Login Security, 2FA, Firewall, Brute Force Prevention v3.2.4
3.2.4 3.2.3 3.2.2 3.2.1 3.2.0 trunk 2.0.0 2.1.0 2.10.0 2.10.1 2.11.0 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.14.0 2.15.0 2.15.1 2.15.2 2.16.0 2.17.0 2.17.1 2.17.2 2.17.3 2.17.4 2.18.0 2.19.0 2.19.1 2.19.2 2.2.0 2.20.0 2.20.1 2.20.2 2.20.3 2.20.4 2.20.5 2.20.6 2.21.0 2.21.1 2.22.0 2.22.1 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.25.0 2.25.1 2.25.10 2.25.11 2.25.12 2.25.13 2.25.14 2.25.15 2.25.16 2.25.17 2.25.18 2.25.19 2.25.2 2.25.20 2.25.21 2.25.22 2.25.23 2.25.24 2.25.25 2.25.26 2.25.27 2.25.28 2.25.29 2.25.3 2.25.4 2.25.5 2.25.6 2.25.7 2.25.8 2.25.9 2.26.0 2.26.1 2.26.10 2.26.11 2.26.12 2.26.13 2.26.14 2.26.15 2.26.16 2.26.17 2.26.18 2.26.19 2.26.2 2.26.20 2.26.21 2.26.22 2.26.23 2.26.24 2.26.25 2.26.26 2.26.27 2.26.28 2.26.3 2.26.4 2.26.5 2.26.6 2.26.7 2.26.8 2.26.9 2.3.0 2.4.0 2.5.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.8.0 2.8.1 2.9.0 3.0.0 3.0.1 3.0.2 3.1.0
limit-login-attempts-reloaded / core / mfa / MfaSettings.php
limit-login-attempts-reloaded / core / mfa Last commit date
rescuepayloadstorage 2 weeks ago MfaBackupCodes.php 2 weeks ago MfaBackupCodesInterface.php 2 weeks ago MfaEndpoint.php 2 weeks ago MfaEndpointInterface.php 2 weeks ago MfaManager.php 2 weeks ago MfaSettings.php 2 weeks ago MfaSettingsInterface.php 2 weeks ago MfaValidator.php 2 weeks ago RescueCode.php 2 weeks ago
MfaSettings.php
133 lines
1 <?php
2
3 namespace LLAR\Core\Mfa;
4
5 use LLAR\Core\Config;
6 use LLAR\Core\MfaConstants;
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * MFA settings: view data, cleanup, temporarily disabled state.
14 * Uses MfaValidator for block reason; MfaBackupCodes for rescue-popup logic.
15 */
16 class MfaSettings implements MfaSettingsInterface {
17
18 /**
19 * Whether MFA is temporarily disabled (rescue flow).
20 * When transient expires, we do not auto-enable MFA so admin's explicit disable is preserved.
21 *
22 * @return bool
23 */
24 public function is_mfa_temporarily_disabled() {
25 return false !== get_transient( MfaConstants::TRANSIENT_MFA_DISABLED );
26 }
27
28 /**
29 * Reason MFA is temporarily disabled: 'api_unreachable' or 1 (rescue link). Null when not disabled.
30 *
31 * @return string|int|null
32 */
33 public function get_mfa_disabled_reason() {
34 if ( ! $this->is_mfa_temporarily_disabled() ) {
35 return null;
36 }
37 $value = get_transient( MfaConstants::TRANSIENT_MFA_DISABLED );
38 return $value;
39 }
40
41 /**
42 * Cleanup rescue codes and MFA transients when MFA is disabled.
43 *
44 * @return void
45 */
46 public function cleanup_rescue_codes() {
47 Config::delete( 'mfa_rescue_codes' );
48 Config::delete( 'mfa_rescue_download_token' );
49 $this->delete_mfa_transients();
50 }
51
52 /**
53 * Delete MFA transients via prepared statements.
54 */
55 private function delete_mfa_transients() {
56 global $wpdb;
57
58 // Cleanup general MFA-related transients.
59 $like = $wpdb->esc_like( '_transient_llar_mfa' ) . '%';
60 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE %s', $like ) );
61 $like_timeout = $wpdb->esc_like( '_transient_timeout_llar_mfa' ) . '%';
62 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE %s', $like_timeout ) );
63
64 // Cleanup rescue-link transients (one per hash_id).
65 $like_rescue = $wpdb->esc_like( '_transient_' . MfaConstants::TRANSIENT_RESCUE_PREFIX ) . '%';
66 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE %s', $like_rescue ) );
67 $like_rescue_timeout = $wpdb->esc_like( '_transient_timeout_' . MfaConstants::TRANSIENT_RESCUE_PREFIX ) . '%';
68 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE %s', $like_rescue_timeout ) );
69 }
70
71 /**
72 * Prepare roles for MFA tab. Caches get_editable_roles() per request to avoid repeated calls.
73 *
74 * @return array prepared_roles, editable_roles
75 */
76 public function prepare_roles_data() {
77 static $editable_roles = null;
78 if ( null === $editable_roles ) {
79 $editable_roles = get_editable_roles();
80 }
81 $prepared_roles = array();
82 foreach ( $editable_roles as $role_key => $role_data ) {
83 $prepared_roles[ $role_key ] = esc_html( translate_user_role( $role_data['name'] ) );
84 }
85 return array(
86 'prepared_roles' => $prepared_roles,
87 'editable_roles' => $editable_roles,
88 );
89 }
90
91 /**
92 * MFA settings for view. Single source; uses MfaValidator for block reason.
93 *
94 * @param bool $show_rescue_popup From form submit when popup should open.
95 * @return array mfa_enabled, mfa_temporarily_disabled, mfa_disabled_reason, mfa_roles, prepared_roles, editable_roles, show_rescue_popup, mfa_block_reason, mfa_block_message
96 */
97 public function get_settings_for_view( $show_rescue_popup = false ) {
98 $mfa_enabled_raw = Config::get( 'mfa_enabled', false );
99 $mfa_temporarily_disabled = $this->is_mfa_temporarily_disabled();
100 $mfa_disabled_reason = $this->get_mfa_disabled_reason();
101 $mfa_checkbox_state = get_transient( MfaConstants::TRANSIENT_CHECKBOX_STATE );
102
103 // When temporarily disabled, keep checkbox state aligned with persistent config so that
104 // after transient expires MFA is effectively on again without user action.
105 $mfa_enabled = ( $mfa_enabled_raw && ! $mfa_temporarily_disabled ) || ( 1 === $mfa_checkbox_state )
106 || ( $mfa_temporarily_disabled && $mfa_enabled_raw );
107
108 $mfa_roles = Config::get( 'mfa_roles', array() );
109 if ( ! is_array( $mfa_roles ) ) {
110 $mfa_roles = array();
111 }
112
113 $roles_data = $this->prepare_roles_data();
114 $codes = Config::get( 'mfa_rescue_codes', array() );
115 // Only show rescue popup when MFA is enabled or user just enabled it (checkbox state).
116 $mfa_should_show = $mfa_enabled_raw || ( 1 === $mfa_checkbox_state );
117 $show_popup = $mfa_should_show && ( $show_rescue_popup || MfaBackupCodes::should_show_rescue_popup( $codes ) );
118 $mfa_block_reason = MfaValidator::get_block_reason();
119
120 return array(
121 'mfa_enabled' => $mfa_enabled,
122 'mfa_temporarily_disabled' => $mfa_temporarily_disabled,
123 'mfa_disabled_reason' => $mfa_disabled_reason,
124 'mfa_roles' => $mfa_roles,
125 'prepared_roles' => $roles_data['prepared_roles'],
126 'editable_roles' => $roles_data['editable_roles'],
127 'show_rescue_popup' => $show_popup,
128 'mfa_block_reason' => $mfa_block_reason,
129 'mfa_block_message' => $mfa_block_reason ? MfaValidator::get_block_message( $mfa_block_reason ) : '',
130 );
131 }
132 }
133