PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.4.0
Defender Security – Malware Scanner, Login Security & Firewall v5.4.0
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 / audit / class-users-audit.php

class-users-audit.php in Defender Security – Malware Scanner, Login Security & Firewall 5.4.0, at src/component/audit/class-users-audit.php

445 lines 13.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles user-related audit events.
4 *
5 * @package WP_Defender\Component\Audit
6 */
7
8 namespace WP_Defender\Component\Audit;
9
10 use WP_User;
11 use WP_Defender\Traits\User;
12 use WP_Defender\Model\Audit_Log;
13
14 /**
15 * Handle user-related audit events such as login, logout, registration, and profile updates.
16 */
17 class Users_Audit extends Audit_Event {
18
19 use User;
20
21 public const ACTION_LOGIN = 'login', ACTION_LOGOUT = 'logout', ACTION_REGISTERED = 'registered',
22 ACTION_LOST_PASS = 'lost_password', ACTION_RESET_PASS = 'reset_password';
23
24 public const CONTEXT_SESSION = 'session', CONTEXT_USERS = 'users', CONTEXT_PROFILE = 'profile';
25
26 /**
27 * Returns an array of hooks associated with various user actions to capture and log them.
28 *
29 * @return array
30 */
31 public function get_hooks(): array {
32
33 return array(
34 'wp_login_failed' => array(
35 'args' => array( 'username' ),
36 'text' => sprintf(
37 /* translators: 1: Blog name, 2: Username */
38 esc_html__( '%1$s User login fail. Username: %2$s', 'defender-security' ),
39 '{{blog_name}}',
40 '{{username}}'
41 ),
42 'event_type' => Audit_Log::EVENT_TYPE_USER,
43 'context' => self::CONTEXT_SESSION,
44 'action_type' => self::ACTION_LOGIN,
45 ),
46 'wp_login' => array(
47 'args' => array( 'userlogin', 'user' ),
48 'text' => sprintf(
49 /* translators: 1: Blog name, 2: Username */
50 esc_html__( '%1$s User login success: %2$s', 'defender-security' ),
51 '{{blog_name}}',
52 '{{userlogin}}'
53 ),
54 'event_type' => Audit_Log::EVENT_TYPE_USER,
55 'context' => self::CONTEXT_SESSION,
56 'action_type' => self::ACTION_LOGIN,
57 ),
58 'wpmu_2fa_login' => array(
59 'args' => array( 'user_id', '2fa_slug' ),
60 'text' => sprintf(
61 /* translators: 1: Blog name, 2: 2fa method slug, 3: Username. */
62 esc_html__( '%1$s 2fa with %2$s method login success for user: %3$s', 'defender-security' ),
63 '{{blog_name}}',
64 '{{2fa_slug}}',
65 '{{username}}'
66 ),
67 'event_type' => Audit_Log::EVENT_TYPE_USER,
68 'context' => self::CONTEXT_SESSION,
69 'action_type' => self::ACTION_LOGIN,
70 'program_args' => array(
71 'username' => array(
72 'callable' => 'get_user_by',
73 'params' => array(
74 'id',
75 '{{user_id}}',
76 ),
77 'result_property' => 'user_login',
78 ),
79 ),
80 ),
81 'wp_logout' => array(
82 'args' => array( 'user_id' ),
83 'text' => sprintf(
84 /* translators: 1: Blog name, 2: Username */
85 esc_html__( '%1$s User logout success: %2$s', 'defender-security' ),
86 '{{blog_name}}',
87 '{{username}}'
88 ),
89 'event_type' => Audit_Log::EVENT_TYPE_USER,
90 'action_type' => self::ACTION_LOGOUT,
91 'context' => self::CONTEXT_SESSION,
92 'program_args' => array(
93 'username' => array(
94 'callable' => 'get_user_by',
95 'params' => array(
96 'id',
97 '{{user_id}}',
98 ),
99 'result_property' => 'user_login',
100 ),
101 ),
102 ),
103 'user_register' => array(
104 'args' => array( 'user_id' ),
105 'text' => is_admin()
106 ? sprintf(
107 /* translators: 1: Blog name, 2: Source of action. For e.g. Hub or a logged-in user, 3: Username, 4: User role */
108 esc_html__( '%1$s %2$s added a new user: Username: %3$s, Role: %4$s', 'defender-security' ),
109 '{{blog_name}}',
110 '{{wp_user}}',
111 '{{username}}',
112 '{{user_role}}'
113 )
114 : sprintf(
115 /* translators: 1: Blog name, 2: Username, 3: User role */
116 esc_html__( '%1$s A new user registered: Username: %2$s, Role: %3$s', 'defender-security' ),
117 '{{blog_name}}',
118 '{{username}}',
119 '{{user_role}}'
120 ),
121 'event_type' => Audit_Log::EVENT_TYPE_USER,
122 'context' => self::CONTEXT_USERS,
123 'action_type' => self::ACTION_REGISTERED,
124 'program_args' => array(
125 'username' => array(
126 'callable' => 'get_user_by',
127 'params' => array(
128 'id',
129 '{{user_id}}',
130 ),
131 'result_property' => 'user_login',
132 ),
133 'user_role' => array(
134 'callable' => array( self::class, 'get_user_role' ),
135 'params' => array(
136 '{{user_id}}',
137 ),
138 ),
139 ),
140 ),
141 'delete_user' => array(
142 'args' => array( 'user_id' ),
143 'text' => sprintf(
144 /* translators: 1: Blog name, 2: Source of action. For e.g. Hub or a logged-in user, 3: User ID, 4: Username */
145 esc_html__( '%1$s %2$s deleted a user: ID: %3$s, username: %4$s', 'defender-security' ),
146 '{{blog_name}}',
147 '{{wp_user}}',
148 '{{user_id}}',
149 '{{username}}'
150 ),
151 'context' => self::CONTEXT_USERS,
152 'action_type' => self::ACTION_DELETED,
153 'event_type' => Audit_Log::EVENT_TYPE_USER,
154 'program_args' => array(
155 'username' => array(
156 'callable' => 'get_user_by',
157 'params' => array(
158 'id',
159 '{{user_id}}',
160 ),
161 'result_property' => 'user_login',
162 ),
163 ),
164 ),
165 'remove_user_from_blog' => array(
166 'args' => array( 'user_id', 'blog_id' ),
167 'context' => self::CONTEXT_USERS,
168 'action_type' => self::ACTION_DELETED,
169 'event_type' => Audit_Log::EVENT_TYPE_USER,
170 'callback' => array( self::class, 'remove_user_from_blog_callback' ),
171 ),
172 'wpmu_delete_user' => array(
173 'args' => array( 'user_id' ),
174 'text' => sprintf(
175 /* translators: 1: Blog name, 2: Source of action. For e.g. Hub or a logged-in user, 3: User ID, 4: Username */
176 esc_html__( '%1$s %2$s deleted a user: ID: %3$s, username: %4$s', 'defender-security' ),
177 '{{blog_name}}',
178 '{{wp_user}}',
179 '{{user_id}}',
180 '{{username}}'
181 ),
182 'context' => self::CONTEXT_USERS,
183 'action_type' => self::ACTION_DELETED,
184 'event_type' => Audit_Log::EVENT_TYPE_USER,
185 'program_args' => array(
186 'username' => array(
187 'callable' => 'get_user_by',
188 'params' => array(
189 'id',
190 '{{user_id}}',
191 ),
192 'result_property' => 'user_login',
193 ),
194 ),
195 ),
196 'profile_update' => array(
197 'args' => array( 'user_id', 'old_user_data' ),
198 'action_type' => self::ACTION_UPDATED,
199 'event_type' => Audit_Log::EVENT_TYPE_USER,
200 'context' => self::CONTEXT_PROFILE,
201 'callback' => array( self::class, 'profile_update_callback' ),
202 ),
203 'retrieve_password' => array(
204 'args' => array( 'username' ),
205 'text' => sprintf(
206 /* translators: 1: Blog name, 2: Username */
207 esc_html__( '%1$s Password requested to reset for user: %2$s', 'defender-security' ),
208 '{{blog_name}}',
209 '{{username}}'
210 ),
211 'action_type' => self::ACTION_LOST_PASS,
212 'event_type' => Audit_Log::EVENT_TYPE_USER,
213 'context' => self::CONTEXT_PROFILE,
214 'program_args' => array(
215 'user' => array(
216 'callable' => 'get_user_by',
217 'params' => array(
218 'login',
219 '{{username}}',
220 ),
221 ),
222 ),
223 ),
224 'after_password_reset' => array(
225 'args' => array( 'user' ),
226 'text' => sprintf(
227 /* translators: 1: Blog name, 2: Username. */
228 esc_html__( '%1$s Password reset for user: %2$s', 'defender-security' ),
229 '{{blog_name}}',
230 '{{user_login}}'
231 ),
232 'event_type' => Audit_Log::EVENT_TYPE_USER,
233 'action_type' => self::ACTION_RESET_PASS,
234 'context' => self::CONTEXT_PROFILE,
235 'custom_args' => array(
236 'user_login' => '{{user->user_login}}',
237 ),
238 ),
239 'set_user_role' => array(
240 'args' => array( 'user_ID', 'new_role', 'old_role' ),
241 'text' => sprintf(
242 /* translators: 1: Blog name, 2: Source of action. For e.g. Hub or a logged-in user, 3: Username, 4: Old user role, 5: New user role */
243 esc_html__( "%1\$s %2\$s changed user %3\$s's role from %4\$s to %5\$s", 'defender-security' ),
244 '{{blog_name}}',
245 '{{wp_user}}',
246 '{{username}}',
247 '{{from_role}}',
248 '{{new_role}}'
249 ),
250 'action_type' => self::ACTION_UPDATED,
251 'event_type' => Audit_Log::EVENT_TYPE_USER,
252 'context' => self::CONTEXT_PROFILE,
253 'custom_args' => array(
254 'from_role' => '{{old_role->0}}',
255 ),
256 'program_args' => array(
257 'username' => array(
258 'callable' => 'get_user_by',
259 'params' => array(
260 'id',
261 '{{user_ID}}',
262 ),
263 'result_property' => 'user_login',
264 ),
265 ),
266 'false_when' => array(
267 array(
268 '{{old_role}}',
269 array(),
270 '==',
271 ),
272 ),
273 ),
274 'wpdef_session_lock' => array(
275 'args' => array( 'user_id', 'session_lock_type' ),
276 'text' => sprintf(
277 /* translators: 1: Blog name, 2: Username, 3: Session lock type. */
278 esc_html__( '%1$s User session ended for %2$s due to a change in %3$s', 'defender-security' ),
279 '{{blog_name}}',
280 '{{username}}',
281 '{{session_lock_type}}'
282 ),
283 'event_type' => Audit_Log::EVENT_TYPE_USER,
284 'context' => self::CONTEXT_SESSION,
285 'action_type' => self::ACTION_LOGIN,
286 'program_args' => array(
287 'username' => array(
288 'callable' => 'get_user_by',
289 'params' => array(
290 'id',
291 '{{user_id}}',
292 ),
293 'result_property' => 'user_login',
294 ),
295 ),
296 ),
297 'wpdef_session_timeout' => array(
298 'args' => array( 'user_id' ),
299 'text' => sprintf(
300 /* translators: 1: Blog name, 2: Username. */
301 esc_html__( '%1$s User session ended for %2$s due to an idle session', 'defender-security' ),
302 '{{blog_name}}',
303 '{{username}}'
304 ),
305 'event_type' => Audit_Log::EVENT_TYPE_USER,
306 'context' => self::CONTEXT_SESSION,
307 'action_type' => self::ACTION_LOGIN,
308 'program_args' => array(
309 'username' => array(
310 'callable' => 'get_user_by',
311 'params' => array(
312 'id',
313 '{{user_id}}',
314 ),
315 'result_property' => 'user_login',
316 ),
317 ),
318 ),
319 );
320 }
321
322 /**
323 * Log when user is removed from a blog.
324 *
325 * @return bool|array
326 */
327 public function remove_user_from_blog_callback() {
328 if ( self::is_create_user_action() ) {
329 return false;
330 }
331
332 $args = func_get_args();
333 $user_id = $args[1]['user_id'];
334 $blog_id = $args[1]['blog_id'];
335 $user = get_user_by( 'id', $user_id );
336 $username = $user->user_login ?? '';
337 $current_user_display = $this->get_user_display( get_current_user_id() );
338 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
339
340 return array(
341 sprintf(
342 /* translators: 1: Blog name, 2: User's display name, 3: User ID, 4: Username, 5: Blog ID */
343 esc_html__( '%1$s %2$s removed a user: ID: %3$s, username: %4$s from blog %5$s', 'defender-security' ),
344 $blog_name,
345 $current_user_display,
346 $user_id,
347 $username,
348 $blog_id
349 ),
350 self::ACTION_DELETED,
351 );
352 }
353
354 /**
355 * Callback for logging when a user's profile is updated. It distinguishes between self-updates and updates made by
356 * other users.
357 *
358 * @return bool|array
359 */
360 public function profile_update_callback() {
361 if ( self::is_create_user_action() ) {
362 return false;
363 }
364
365 $args = func_get_args();
366 $user_id = $args[1]['user_id'];
367 $current_user = get_user_by( 'id', $user_id );
368 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
369 $current_user_id = get_current_user_id();
370
371 if ( $current_user_id === $user_id ) {
372
373 return array(
374 sprintf(
375 /* translators: 1: Blog name, 2: User's nicename */
376 esc_html__( '%1$s User %2$s updated his/her profile', 'defender-security' ),
377 $blog_name,
378 $current_user->user_nicename
379 ),
380 self::ACTION_UPDATED,
381 );
382 } elseif ( 0 !== $current_user_id ) {
383
384 return array(
385 sprintf(
386 /* translators: 1: Blog name, 2: User's display name, 3: User's nicename */
387 esc_html__( "%1\$s %2\$s updated user %3\$s's profile information", 'defender-security' ),
388 $blog_name,
389 $this->get_user_display( $current_user_id ),
390 $current_user->user_nicename
391 ),
392 self::ACTION_UPDATED,
393 );
394 }
395 }
396
397 /**
398 * Provides a dictionary for translating action constants into human-readable strings.
399 *
400 * @return array
401 */
402 public function dictionary(): array {
403 return array(
404 self::ACTION_LOST_PASS => esc_html__( 'lost password', 'defender-security' ),
405 self::ACTION_REGISTERED => esc_html__( 'registered', 'defender-security' ),
406 self::ACTION_LOGIN => esc_html__( 'login', 'defender-security' ),
407 self::ACTION_LOGOUT => esc_html__( 'logout', 'defender-security' ),
408 self::ACTION_RESET_PASS => esc_html__( 'password reset', 'defender-security' ),
409 );
410 }
411
412 /**
413 * Static method to retrieve the role of a user by their ID
414 *
415 * @param int $user_id The ID of the user whose role is to be fetched.
416 *
417 * @return string
418 */
419 public static function get_user_role( $user_id ): string {
420 $user = get_user_by( 'id', $user_id );
421 if ( $user instanceof WP_User ) {
422 $_this = new self();
423
424 return $_this->get_first_user_role( $user );
425 } else {
426 return '';
427 }
428 }
429
430 /**
431 * Check if it is a create new user request.
432 *
433 * @since 2.8.0
434 * @retun bool
435 */
436 public static function is_create_user_action(): bool {
437 $action = defender_get_data_from_request( 'action', 'p' );
438 if ( 'createuser' === $action ) {
439 return true;
440 }
441
442 return false;
443 }
444 }
445