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-flow / MfaApiClient.php
limit-login-attempts-reloaded / core / mfa-flow Last commit date
Providers 2 weeks ago CallbackHandler.php 2 weeks ago MfaApiClient.php 2 weeks ago MfaFlowSendCode.php 2 weeks ago MfaProviderRegistry.php 2 weeks ago MfaRestApi.php 2 weeks ago SessionStore.php 2 weeks ago
MfaApiClient.php
138 lines
1 <?php
2
3 namespace LLAR\Core\MfaFlow;
4
5 use LLAR\Core\Helpers;
6 use LLAR\Core\Http\Http;
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * MFA API client: handshake and verify via existing HTTP transport.
14 * Uses LLA_MFA_API_BASE_URL + LLA_MFA_API_PATH constants; options may override base_url.
15 */
16 class MfaApiClient {
17
18 /**
19 * Default MFA API base URL (base + path from constants).
20 *
21 * @return string
22 */
23 private static function get_default_base_url() {
24 $base = defined( 'LLA_MFA_API_BASE_URL' ) ? rtrim( (string) LLA_MFA_API_BASE_URL, '/' ) : 'https://api.limitloginattempts.com';
25 $path = defined( 'LLA_MFA_API_PATH' ) ? (string) LLA_MFA_API_PATH : '/mfa';
26 if ( $path !== '' && substr( $path, 0, 1 ) !== '/' ) {
27 $path = '/' . $path;
28 }
29 return $path !== '' ? $base . $path : $base;
30 }
31
32 /**
33 * Call POST /wp/handshake.
34 *
35 * @param array $payload user_ip, login_url, send_email_url (required per API), user_group, is_pre_authenticated.
36 * @param array $options Optional. base_url (override constants).
37 * @return array { success: bool, data: array|null, error: string|null, server_unreachable?: bool }
38 */
39 public function handshake( array $payload, $options = array() ) {
40 $base = isset( $options['base_url'] ) && (string) $options['base_url'] !== '' ? rtrim( (string) $options['base_url'], '/' ) : self::get_default_base_url();
41 if ( '' === $base ) {
42 return array(
43 'success' => false,
44 'data' => null,
45 'error' => 'MFA API endpoint not configured',
46 );
47 }
48
49 $url = $base . '/wp/handshake';
50 $request_options = array( 'data' => $payload );
51 if ( defined( 'LLA_MFA_API_TOKEN' ) && LLA_MFA_API_TOKEN !== '' ) {
52 $request_options['headers'] = array( 'Authorization: Bearer ' . (string) LLA_MFA_API_TOKEN );
53 }
54 $response = Http::post( $url, $request_options );
55 $status = isset( $response['status'] ) ? (int) $response['status'] : 0;
56
57 $result = $this->parse_response( $response, $url );
58 if ( ! $result['success'] && 0 === $status ) {
59 $result['server_unreachable'] = true;
60 }
61 return $result;
62 }
63
64 /**
65 * Call POST /wp/verify.
66 *
67 * @param string $token Session token.
68 * @param string $secret Session secret.
69 * @param array $options Optional. base_url (override constants).
70 * @return array { success: bool, data: array|null, error: string|null }
71 */
72 public function verify( $token, $secret, $options = array() ) {
73 $base = isset( $options['base_url'] ) && (string) $options['base_url'] !== '' ? rtrim( (string) $options['base_url'], '/' ) : self::get_default_base_url();
74 if ( '' === $base ) {
75 return array(
76 'success' => false,
77 'data' => null,
78 'error' => 'MFA API endpoint not configured',
79 );
80 }
81
82 $url = $base . '/wp/verify';
83 $request_options = array(
84 'data' => array(
85 'token' => $token,
86 'secret' => $secret,
87 ),
88 );
89 if ( defined( 'LLA_MFA_API_TOKEN' ) && LLA_MFA_API_TOKEN !== '' ) {
90 $request_options['headers'] = array( 'Authorization: Bearer ' . (string) LLA_MFA_API_TOKEN );
91 }
92 $response = Http::post( $url, $request_options );
93
94 $result = $this->parse_response( $response, $url );
95 $status = isset( $response['status'] ) ? (int) $response['status'] : 0;
96 return $result;
97 }
98
99 /**
100 * Parse transport response into success/data/error.
101 *
102 * @param array $response With keys data, status, error.
103 * @param string $url Request URL for logging.
104 * @return array { success: bool, data: array|null, error: string|null }
105 */
106 private function parse_response( $response, $url ) {
107 $status = isset( $response['status'] ) ? (int) $response['status'] : 0;
108 $body = isset( $response['data'] ) ? $response['data'] : '';
109 $err = isset( $response['error'] ) ? $response['error'] : null;
110
111 if ( 200 !== $status ) {
112 $decoded = is_string( $body ) ? json_decode( $body, true ) : null;
113 $message = ( is_array( $decoded ) && ! empty( $decoded['message'] ) ) ? $decoded['message'] : $err;
114 return array(
115 'success' => false,
116 'data' => null,
117 'error' => $message ? $message : 'Request failed',
118 );
119 }
120
121 $data = is_string( $body ) ? json_decode( $body, true ) : null;
122 if ( ! is_array( $data ) ) {
123 return array(
124 'success' => false,
125 'data' => null,
126 'error' => 'Invalid response',
127 );
128 }
129
130 $data = Helpers::sanitize_stripslashes_deep( $data );
131 return array(
132 'success' => true,
133 'data' => $data,
134 'error' => null,
135 );
136 }
137 }
138