PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.3.1
Defender Security – Malware Scanner, Login Security & Firewall v5.3.1
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / component / class-webauthn.php

class-webauthn.php in Defender Security – Malware Scanner, Login Security & Firewall 5.3.1, at src/component/class-webauthn.php

254 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles WebAuthn functionalities providing methods to manage and verify user credentials.
4 *
5 * @package WP_Defender\Component
6 */
7
8 namespace WP_Defender\Component;
9
10 use WP_User;
11 use Webauthn\PublicKeyCredentialSource;
12 use Webauthn\PublicKeyCredentialUserEntity;
13 use WP_Defender\Traits\Webauthn as Webauthn_Trait;
14 use Webauthn\PublicKeyCredentialSourceRepository;
15
16 /**
17 * Handles WebAuthn functionalities providing methods to manage and verify user credentials.
18 *
19 * @since 3.0.0
20 */
21 class Webauthn implements PublicKeyCredentialSourceRepository {
22
23 use Webauthn_Trait;
24
25 /**
26 * Option key for storing user credentials.
27 *
28 * @var string
29 */
30 public const CREDENTIAL_OPTION_KEY = 'user_credentials';
31
32 /**
33 * Meta key for storing credentials having userHandle mismatch.
34 *
35 * @var string
36 */
37 public const USER_HANDLE_MISMATCH_KEY = 'user_handle_match_failed';
38
39 /**
40 * Get user credentials.
41 *
42 * @param int $user_id The user ID.
43 *
44 * @return mixed
45 */
46 public function getCredentials( int $user_id ) {
47 return $this->get_user_meta( $user_id, self::CREDENTIAL_OPTION_KEY );
48 }
49
50 /**
51 * Set user credentials.
52 *
53 * @param int $user_id The user ID.
54 * @param array $data The credentials data.
55 *
56 * @return bool
57 */
58 public function setCredentials( int $user_id, array $data ): bool {
59 return false !== $this->update_user_meta( $user_id, self::CREDENTIAL_OPTION_KEY, $data );
60 }
61
62 /**
63 * Get one credential by credential ID.
64 *
65 * @param string $public_key_credential_id The public key credential ID.
66 *
67 * @return PublicKeyCredentialSource|null
68 */
69 public function findOneByCredentialId( string $public_key_credential_id ): ?PublicKeyCredentialSource {
70 $username = defender_get_data_from_request( 'username', 'p' );
71 if ( isset( $username ) ) {
72 $user = get_user_by( 'login', $username );
73
74 if ( is_object( $user ) ) {
75 $user_id = $user->ID;
76 } else {
77 $user_id = 0;
78 }
79 } else {
80 $user_id = get_current_user_id();
81 }
82 $data = $this->getCredentials( $user_id );
83 if ( isset( $data[ base64_encode( $public_key_credential_id ) ]['credential_source'] ) ) { // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
84 return PublicKeyCredentialSource::createFromArray( $data[ base64_encode( $public_key_credential_id ) ]['credential_source'] ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
85 }
86
87 return null;
88 }
89
90 /**
91 * Get all credentials of a user
92 *
93 * @param PublicKeyCredentialUserEntity $public_key_credential_user_entity The user entity.
94 *
95 * @return array
96 */
97 public function findAllForUserEntity( PublicKeyCredentialUserEntity $public_key_credential_user_entity ): array {
98 $credentials = array();
99 $username = $public_key_credential_user_entity->getName();
100 $user = get_user_by( 'login', $username );
101
102 if ( is_object( $user ) ) {
103 $credentials = $this->findAllForUserByType( $user->ID );
104 }
105
106 return $credentials;
107 }
108
109 /**
110 * Get all credentials of a user by authenticator type.
111 *
112 * @param int $user_id The user ID.
113 * @param null|string $type The type of authenticator.
114 *
115 * @return array
116 * @since 3.1.0
117 */
118 public function findAllForUserByType( int $user_id, $type = null ): array {
119 $sources = array();
120 $user_data = $this->getCredentials( $user_id );
121
122 if ( is_array( $user_data ) ) {
123 foreach ( $user_data as $data ) {
124 if ( ! empty( $type ) && ! empty( $data['authenticator_type'] ) && $type !== $data['authenticator_type'] ) {
125 continue;
126 }
127
128 if ( isset( $data['credential_source'] ) ) {
129 $sources[] = PublicKeyCredentialSource::createFromArray( $data['credential_source'] );
130 }
131 }
132 }
133
134 return $sources;
135 }
136
137 /**
138 * Store credential into database.
139 *
140 * @param PublicKeyCredentialSource $public_key_credential_source The credential source to store.
141 *
142 * @return void
143 */
144 public function saveCredentialSource( PublicKeyCredentialSource $public_key_credential_source ): void {
145 $user_id = get_current_user_id();
146 $data = $this->getCredentials( $user_id );
147 $key = base64_encode( $public_key_credential_source->getPublicKeyCredentialId() ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
148
149 if ( ! isset( $data[ $key ] ) ) {
150 $data[ $key ] = array(
151 'label' => defender_get_data_from_request( 'name', 'p' ) ?? '',
152 'added' => time(),
153 'authenticator_type' => defender_get_data_from_request( 'type', 'p' ) ?? '',
154 'user' => $public_key_credential_source->getUserHandle(),
155 'credential_source' => $public_key_credential_source,
156 );
157 } else {
158 $data[ $key ]['credential_source'] = $public_key_credential_source;
159 }
160
161 $this->setCredentials( $user_id, $data );
162 }
163
164 /**
165 * Get userHandle mismatch list.
166 *
167 * @param int $user_id The user ID.
168 *
169 * @return array
170 * @since 3.4.0
171 */
172 public function getUserHandleMatchFailed( int $user_id ): array {
173 $meta_key = $this->option_prefix . self::USER_HANDLE_MISMATCH_KEY;
174 $meta_val = get_user_meta( $user_id, $meta_key, true );
175
176 return is_array( $meta_val ) ? $meta_val : array();
177 }
178
179 /**
180 * Set userHandle mismatch list.
181 *
182 * @param int $user_id The user ID.
183 * @param array $meta_val The mismatches to set.
184 *
185 * @return void
186 * @since 3.4.0
187 */
188 public function setUserHandleMatchFailed( int $user_id, array $meta_val ): void {
189 $meta_key = $this->option_prefix . self::USER_HANDLE_MISMATCH_KEY;
190 update_user_meta( $user_id, $meta_key, $meta_val );
191 }
192
193 /**
194 * Add authenticators to userHandle mismatch list.
195 *
196 * @param WP_User $user The user object.
197 * @param array $data The data to add.
198 *
199 * @return void
200 * @since 3.4.0
201 */
202 public function addUserHandleMatchFailed( $user, $data ): void {
203 if ( ! empty( $user->ID ) && ! empty( $data['rawId'] ) ) {
204 $meta_val = $this->getUserHandleMatchFailed( $user->ID );
205 $meta_val['show_notice'] = $meta_val['show_notice'] ?? true;
206
207 if ( empty( $meta_val['authenticators'] ) || ! in_array( $data['rawId'], $meta_val['authenticators'], true ) ) {
208 $meta_val['authenticators'][] = $data['rawId'];
209 }
210
211 $this->setUserHandleMatchFailed( $user->ID, $meta_val );
212 }
213 }
214
215 /**
216 * Remove authenticator from userHandle mismatch list.
217 *
218 * @param int $user_id The user ID.
219 * @param string $auth_id The authenticator ID to remove.
220 *
221 * @return void
222 * @since 3.4.0
223 */
224 public function removeUserHandleMatchFailed( int $user_id, string $auth_id ): void {
225 if ( ! empty( $auth_id ) ) {
226 $meta_val = $this->getUserHandleMatchFailed( $user_id );
227
228 if ( ! empty( $meta_val['authenticators'] ) && is_array( $meta_val['authenticators'] ) ) {
229 $pos = array_search( $auth_id, $meta_val['authenticators'], true );
230
231 if ( false !== $pos ) {
232 array_splice( $meta_val['authenticators'], $pos, 1 );
233 $this->setUserHandleMatchFailed( $user_id, $meta_val );
234 }
235 }
236 }
237 }
238
239 /**
240 * Disable userHandle mismatch notice.
241 *
242 * @param int $user_id The user ID.
243 *
244 * @return void
245 * @since 3.4.0
246 */
247 public function disableUserHandleMatchFailedNotice( int $user_id ): void {
248 $meta_val = $this->getUserHandleMatchFailed( $user_id );
249 $meta_val['show_notice'] = false;
250
251 $this->setUserHandleMatchFailed( $user_id, $meta_val );
252 }
253 }
254