PluginProbe ʕ •ᴥ•ʔ
Admin and Site Enhancements (ASE) / 2.5.0
Admin and Site Enhancements (ASE) v2.5.0
9.1.0 9.0.2 9.0.1 9.0.0 8.9.2 8.9.1 8.9.0 8.8.8 8.8.7 8.8.6 8.8.5 8.8.4 8.8.3 8.8.2 8.8.1 8.8.0 8.7.3 8.7.2 8.7.1 8.2.1 8.2.2 8.2.3 8.3.0 8.3.1 8.3.2 8.4.0 8.4.1 8.4.2 8.5.0 8.5.1 8.5.2 8.6.0 8.6.1 8.6.2 8.7.0 5.0.1 5.0.2 5.0.2.1 5.0.2.2 5.0.2.3 5.0.2.4 5.1.0 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.8.0 5.8.1 6.0.0 6.0.3 6.0.4 6.0.5 6.0.5.1 6.0.6 6.0.7 6.0.8.1 6.1.0 6.1.3 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.3.0 6.3.1 6.3.2 6.4.0 6.5.0 6.5.1 6.6.0 6.7.0 6.8.0 6.8.2 6.8.3 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13.1 6.9.13.2 6.9.2 6.9.3 6.9.4 6.9.5 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.2 7.0.2.1 7.0.2.2 7.0.2.3 7.0.3 7.1.0 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2.0 7.2.1 7.3.0 7.3.1 7.3.2 7.3.3 7.4.0 7.4.2 7.4.4 7.4.5 7.4.6 7.4.7 7.4.8 7.5.0 7.5.1 7.5.2 7.5.3 7.5.4 7.6.0 7.6.1 7.6.1.1 7.6.10 7.6.11 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.7.1 7.6.8 7.6.9 7.7.0 7.8.0 7.8.1 7.8.10 7.8.11 7.8.12 7.8.13 7.8.14 7.8.15 7.8.16 7.8.17 7.8.18 7.8.2 7.8.3 7.8.4 7.8.5 7.8.5.1 7.8.6 7.8.7 7.8.8 7.8.9 7.9.0 7.9.1 7.9.10 7.9.11 7.9.2 7.9.3 7.9.4 7.9.5 7.9.6 7.9.7 7.9.8 7.9.9 8.0.0 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.0.6 8.0.7 8.0.8 8.1.0 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 2.0.0 2.1.0 2.2.0 2.3.0 2.4.0 2.5.0 2.6.0 2.7.0 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.2.0 3.3.0 3.4.0 3.5.0 3.6.1 3.7.0 3.8.0 3.9.0 3.9.1 3.9.2 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.9.0 4.9.1 4.9.2 4.9.3 5.0.0
admin-site-enhancements / classes / class-security.php
admin-site-enhancements / classes Last commit date
class-activation.php 3 years ago class-admin-interface.php 3 years ago class-common-methods.php 3 years ago class-content-management.php 3 years ago class-deactivation.php 3 years ago class-disable-components.php 3 years ago class-security.php 3 years ago class-settings-fields-render.php 3 years ago class-settings-sanitization.php 3 years ago class-settings-sections-fields.php 3 years ago class-utilities.php 3 years ago
class-security.php
656 lines
1 <?php
2
3 namespace ASENHA\Classes;
4 use WP_Error;
5
6 /**
7 * Class related to Security features
8 *
9 * @since 1.4.0
10 */
11 class Security {
12
13 /**
14 * Redirect to valid login URL when custom login slug is part of the request URL
15 *
16 * @link https://plugins.trac.wordpress.org/browser/admin-login-url-change/trunk/admin-login-url-change.php#L134
17 * @since 1.4.0
18 */
19 public function redirect_on_custom_login_url() {
20
21 $options = get_option( ASENHA_SLUG_U );
22 $custom_login_slug = $options['custom_login_slug'];
23
24 $url_input = sanitize_text_field( $_SERVER['REQUEST_URI'] );
25
26 // Exclude interim login URL, which is inside modal popup when user is logged out in the background
27 // URL looks like https://www.example.com/wp-login.php?interim-login=1&wp_lang=en_US
28 if ( false !== strpos( $url_input, 'interim-login=1' ) ) {
29
30 remove_action( 'login_head', [ $this, 'redirect_on_default_login_urls' ] );
31
32 }
33
34 // If URL contains the custom login slug, redirect to the login URL with custom login slug in the query parameters
35 if (
36 ( false !== strpos( $url_input, '/' . $custom_login_slug ) ) ||
37 ( false !== strpos( $url_input, '/' . $custom_login_slug . '/' ) ) )
38 {
39 wp_safe_redirect( home_url( 'wp-login.php?' . $custom_login_slug . '&redirect=false' ) );
40 exit();
41
42 }
43
44 }
45
46 /**
47 * Redirect to /not_found when login URL does not contain the custom login slug
48 *
49 * @link https://plugins.trac.wordpress.org/browser/admin-login-url-change/trunk/admin-login-url-change.php#L121
50 * @since 1.4.0
51 */
52 public function redirect_on_default_login_urls() {
53
54 global $interim_login;
55
56 $options = get_option( ASENHA_SLUG_U );
57 $custom_login_slug = $options['custom_login_slug']; // e.g. manage
58 $url_input = sanitize_text_field( $_SERVER['REQUEST_URI'] );
59
60 // Custom login slug is not part of the login URL typed into the browser
61 // e.g. https://www.example.com/wp-admin/ or https://www.example.com/wp-login.php
62 if ( false === strpos( $url_input, $custom_login_slug ) ) {
63
64 if ( 'success' != $interim_login ) {
65
66 wp_safe_redirect( home_url( 'not_found/' ), 302 );
67 exit();
68
69 }
70
71 }
72
73 }
74
75 /**
76 * Redirect to custom login URL on failed login
77 *
78 * @link https://plugins.trac.wordpress.org/browser/admin-login-url-change/trunk/admin-login-url-change.php#L148
79 * @since 1.4.0
80 */
81 public function redirect_to_custom_login_url_on_login_fail() {
82
83 $options = get_option( ASENHA_SLUG_U );
84 $custom_login_slug = $options['custom_login_slug'];
85
86 // Append 'failed_login=true' so we can output custom error message above the login form
87 wp_safe_redirect( home_url( 'wp-login.php?' . $custom_login_slug . '&redirect=false&failed_login=true' ) );
88 exit();
89
90 }
91
92 /**
93 * Redirect to custom login URL on successful logout
94 *
95 * @link https://plugins.trac.wordpress.org/browser/admin-login-url-change/trunk/admin-login-url-change.php#L148
96 * @since 1.4.0
97 */
98 public function redirect_to_custom_login_url_on_logout_success() {
99
100 $options = get_option( ASENHA_SLUG_U );
101 $custom_login_slug = $options['custom_login_slug'];
102
103 // Redirect to the login URL with custom login slug in it
104 wp_safe_redirect( home_url( 'wp-login.php?' . $custom_login_slug . '&redirect=false' ) );
105 exit();
106
107 }
108
109 /**
110 * Make sure user is redirected to dashboard /wp-admin/ when login is successful
111 *
112 * @since 2.5.0
113 */
114 public function redirect_to_dashboard( $username, $user ) {
115
116 wp_safe_redirect( get_admin_url() );
117 exit();
118
119 }
120
121 /**
122 * Maybe allow login if not locked out. Should return WP_Error object if not allowed to login.
123 *
124 * @since 2.5.0
125 */
126 public function maybe_allow_login( $user_or_error, $username, $password ) {
127
128 global $wpdb, $asenha_limit_login;
129 $table_name = $wpdb->prefix . 'asenha_failed_logins';
130
131 // Maybe create table if it does not exist yet, e.g. upgraded from previous version of plugin, so, no activation methods are fired
132 $query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table_name ) );
133
134 if ( $wpdb->get_var( $query ) === $table_name ) {
135 // Table already exists, do nothing.
136 } else {
137 $activation = new Activation;
138 $activation->create_failed_logins_log_table();
139 }
140
141 // Get values from options needed to do various checks
142 $options = get_option( ASENHA_SLUG_U );
143 $login_fails_allowed = $options['login_fails_allowed'];
144 $login_lockout_maxcount = $options['login_lockout_maxcount'];
145 $change_login_url = $options['change_login_url'];
146 $custom_login_slug = $options['custom_login_slug'];
147
148 // Instantiate object to access common methods
149 $common_methods = new Common_Methods;
150
151 // Get user/visitor IP address
152 $ip_address = $common_methods->get_user_ip_address();
153
154 // Check if IP address has failed login attempts recorded in the DB log
155 $sql = $wpdb->prepare("SELECT * FROM `" . $table_name . "` Where `ip_address` = %s", $ip_address);
156 $result = $wpdb->get_results( $sql, ARRAY_A );
157
158 $result_count = count( $result );
159
160 if ( $result_count > 0 ) { // IP address has been recorded in the database.
161
162 // Custom Login URL is enabled
163 if ( array_key_exists( 'change_login_url', $options ) && $options['change_login_url'] ) {
164 $fail_count = $result[0]['fail_count'];
165 } else {
166 $fail_count = $result[0]['fail_count'] + 1;
167 }
168
169 $lockout_count = $result[0]['lockout_count'];
170 $last_fail_on = $result[0]['unixtime'];
171
172 } else {
173
174 $fail_count = 0;
175 $lockout_count = 0;
176 $last_fail_on = '';
177
178 }
179
180 // Initialize the global variable
181 $asenha_limit_login = array (
182 'ip_address' => $ip_address,
183 'request_uri' => sanitize_text_field( $_SERVER['REQUEST_URI'] ),
184 'ip_address_log' => $result,
185 'maybe_lockout' => false,
186 'extended_lockout' => false,
187 'within_lockout_period' => false,
188 'lockout_period' => 0,
189 'lockout_period_remaining' => 0,
190 'login_fails_allowed' => $login_fails_allowed,
191 'login_lockout_maxcount' => $login_lockout_maxcount,
192 // 'default_lockout_period' => 60, // 1 minutes in seconds
193 'default_lockout_period' => 60*15, // 15 minutes in seconds
194 // 'extended_lockout_period' => 3*60, // 3 minutes in seconds
195 'extended_lockout_period' => 24*60*60, // 24 hours in seconds
196 'change_login_url' => $change_login_url, // is custom login URL enabled?
197 'custom_login_slug' => $custom_login_slug,
198 );
199
200 if ( $result_count > 0 ) { // IP address has been recorded in the database.
201
202 // Failed attempts have been recorded and fulfills lockout condition
203 if ( ! empty( $fail_count ) && ( ( $fail_count ) % $login_fails_allowed == 0 ) ) {
204
205 $asenha_limit_login['maybe_lockout'] = true;
206
207 // Has reached max / gone beyond number of lockouts allowed?
208 if ( $lockout_count >= $login_lockout_maxcount ) {
209 $asenha_limit_login['extended_lockout'] = true;
210 $lockout_period = $asenha_limit_login['extended_lockout_period'];
211 } else {
212 $asenha_limit_login['extended_lockout'] = false;
213 $lockout_period = $asenha_limit_login['default_lockout_period'];
214 }
215
216 $asenha_limit_login['lockout_period'] = $lockout_period;
217
218 // User/visitor is still within the lockout period
219 if ( ( time() - $last_fail_on ) <= $asenha_limit_login['lockout_period'] ) {
220
221 $asenha_limit_login['within_lockout_period'] = true;
222 $asenha_limit_login['lockout_period_remaining'] = $asenha_limit_login['lockout_period'] - ( time() - $last_fail_on );
223
224 if ( $asenha_limit_login['lockout_period_remaining'] <= 60 ) {
225
226 // Get remaining lockout period in minutes and seconds
227 $lockout_period_remaining = $asenha_limit_login['lockout_period_remaining'] . ' seconds';
228
229 } elseif ( $asenha_limit_login['lockout_period_remaining'] <= 60*60 ) {
230
231 // Get remaining lockout period in minutes and seconds
232 $lockout_period_remaining = $common_methods->seconds_to_period( $asenha_limit_login['lockout_period_remaining'], 'to-minutes-seconds' );
233
234 } elseif ( $asenha_limit_login['lockout_period_remaining'] > 60*60 && $asenha_limit_login['lockout_period_remaining'] <= 24*60*60 ) {
235
236 // Get remaining lockout period in minutes and seconds
237 $lockout_period_remaining = $common_methods->seconds_to_period( $asenha_limit_login['lockout_period_remaining'], 'to-hours-minutes-seconds' );
238
239 } elseif ( $asenha_limit_login['lockout_period_remaining'] > 24*60*60 ) {
240
241 // Get remaining lockout period in minutes and seconds
242 $lockout_period_remaining = $common_methods->seconds_to_period( $asenha_limit_login['lockout_period_remaining'], 'to-days-hours-minutes-seconds' );
243
244 }
245
246 $error = new WP_Error( 'ip_address_blocked', '<b>WARNING:</b> You\'ve been locked out. You can login again in ' . $lockout_period_remaining . '.' );
247
248 // Prevent redirection loop
249 remove_action( 'wp_login_failed', [ $this, 'redirect_to_custom_login_url_on_login_fail' ] );
250
251 return $error;
252
253 } else { // User/visitor is no longer within the lockout period
254
255 $asenha_limit_login['within_lockout_period'] = false;
256
257 if ( $lockout_count == $login_lockout_maxcount ) {
258
259 // Remove the DB log entry for the current IP address. i.e. release from extended lockout
260
261 $where = array( 'ip_address' => $ip_address );
262 $where_format = array( '%s' );
263
264 // Delete existing data in the database
265 $wpdb->delete(
266 $table_name,
267 $where,
268 $where_format
269 );
270
271 }
272
273 return $user_or_error;
274
275 }
276
277 } else {
278
279 $asenha_limit_login['maybe_lockout'] = false;
280
281 return $user_or_error;
282
283 }
284
285 } else { // IP address has not been recorded in the database.
286
287 return $user_or_error;
288
289 }
290
291 }
292
293 /**
294 * Disable login form inputs via javascript
295 *
296 * @since 2.5.0
297 */
298 public function maybe_hide_login_form() {
299
300 global $asenha_limit_login;
301
302 if ( $asenha_limit_login['within_lockout_period'] ) {
303
304 // Hide logo, login form and the links below it
305 ?>
306 <style type="text/css">
307
308 body.login {
309 background:#f6d6d7;
310 }
311
312 #login h1,
313 #loginform,
314 #login #nav,
315 #backtoblog {
316 display: none;
317 }
318
319 @media screen and (max-height: 550px) {
320
321 #login {
322 padding: 80px 0 20px !important;
323 }
324
325 }
326
327 </style>
328 <?php
329 }
330
331 }
332
333 /**
334 * Log failed login attempts
335 *
336 * @since 2.5.0
337 */
338 public function log_failed_login( $username ) {
339
340 global $wpdb, $asenha_limit_login;
341 $table_name = $wpdb->prefix . 'asenha_failed_logins';
342
343 // Check if the IP address has been used in a failed login attempt before, i.e. has it been recorded in the database?
344 $sql = $wpdb->prepare( "SELECT * FROM `" . $table_name . "` WHERE `ip_address` = %s", $asenha_limit_login['ip_address'] );
345 $result = $wpdb->get_results( $sql, ARRAY_A );
346 $result_count = count( $result );
347
348 // Update logged info for the IP address in the global variable
349 $asenha_limit_login['ip_address_log'] = $result;
350
351 if ( $result_count == 0 ) { // IP address has not been recorded in the database.
352
353 $new_fail_count = 1;
354 $new_lockout_count = 0;
355
356 } else { // IP address has been recorded in the database.
357
358 $new_fail_count = $result[0]['fail_count'] + 1;
359 $new_lockout_count = floor( ( $result[0]['fail_count'] + 1 ) / $asenha_limit_login['login_fails_allowed'] );
360
361 }
362
363 // Get the URL where login failed, i.e. where brute force attack might be happening
364 // $login_url = ( ! empty( $_SERVER['HTTPS'] ) ? 'https://' : 'http://') . sanitize_text_field( $_SERVER['HTTP_HOST'] ) . sanitize_text_field( $_SERVER['REQUEST_URI'] );
365
366 // Time stamps
367 $unixtime = time();
368 if ( function_exists( 'wp_date' ) ) {
369 $datetime_wp = wp_date( 'Y-m-d H:i:s', $unixtime );
370 } else {
371 $datetime_wp = date_i18n( 'Y-m-d H:i:s', $unixtime );
372 }
373
374 $data = array(
375 'ip_address' => $asenha_limit_login['ip_address'],
376 'username' => $username,
377 'fail_count' => $new_fail_count,
378 'lockout_count' => $new_lockout_count,
379 'request_uri' => $asenha_limit_login['request_uri'],
380 'unixtime' => $unixtime,
381 'datetime_wp' => $datetime_wp,
382 'info' => '',
383 );
384
385 $data_format = array(
386 '%s', // string
387 '%s', // string
388 '%d', // integer
389 '%d', // integer
390 '%s', // string
391 '%d', // integer
392 '%s', // string
393 '%s', // string
394 );
395
396 if ( $result_count == 0 ) {
397
398 // Insert into the database
399 $result = $wpdb->insert(
400 $table_name,
401 $data,
402 $data_format
403 );
404
405 } else {
406
407 // $options = get_option( ASENHA_SLUG_U );
408 // $login_fails_allowed = $options['login_fails_allowed'];
409
410 $fail_count = $result[0]['fail_count'];
411 $lockout_count = $result[0]['lockout_count'];
412 $last_fail_on = $result[0]['unixtime'];
413
414 $where = array( 'ip_address' => $asenha_limit_login['ip_address'] );
415 $where_format = array( '%s' );
416
417 // Failed attempts have been recorded and fulfills lockout condition
418 if ( ! empty( $fail_count ) && ( $fail_count % $asenha_limit_login['login_fails_allowed'] == 0 ) ) {
419
420 // Has reached max / gone beyond number of lockouts allowed?
421 if ( $lockout_count >= $asenha_limit_login['login_lockout_maxcount'] ) {
422 $asenha_limit_login['extended_lockout'] = true;
423 $lockout_period = $asenha_limit_login['extended_lockout_period'];
424 } else {
425 $asenha_limit_login['extended_lockout'] = false;
426 $lockout_period = $asenha_limit_login['default_lockout_period'];
427 }
428
429 $asenha_limit_login['lockout_period'] = $lockout_period;
430
431 // User/visitor is still within the lockout period
432 if ( ( time() - $last_fail_on ) <= $asenha_limit_login['lockout_period'] ) {
433
434 // Do nothing
435
436 } else {
437
438 if ( $lockout_count < $asenha_limit_login['login_lockout_maxcount'] ) {
439
440 // Update existing data in the database
441 $wpdb->update(
442 $table_name,
443 $data,
444 $where,
445 $data_format,
446 $where_format
447 );
448
449 }
450
451 }
452
453 } else {
454
455 // Update existing data in the database
456 $wpdb->update(
457 $table_name,
458 $data,
459 $where,
460 $data_format,
461 $where_format
462 );
463
464 }
465
466 }
467
468 }
469
470 /**
471 * Handle login errors
472 *
473 * @link https://developer.wordpress.org/reference/classes/wp_error/#methods
474 * @since 2.5.0
475 */
476 public function login_error_handler( $errors, $redirect_to ) {
477
478 global $asenha_limit_login;
479
480 if ( is_wp_error( $errors ) ) {
481
482 $error_codes = $errors->get_error_codes();
483
484 foreach ( $error_codes as $error_code ) {
485
486 if ( $error_code == 'invalid_username' || $error_code == 'incorrect_password' ) {
487
488 // Remove default error messages that may give out valueable info to hackers
489
490 $errors->remove( 'invalid_username' ); // Outputs info that says username does not exist. May encourage login attempt with a different username instead.
491
492 $errors->remove( 'incorrect_password' ); // Outputs info that implies username exist. May encourage login attempt with a different password.
493
494 // Add a new error message that does not provide useful clues to hackers
495 $errors->add( 'invalid_username_or_incorrect_password', '<b>Error:</b> Invalid username or incorrect password.' );
496
497 // $errors->add( 'another_error_code', 'The error message.' );
498
499 }
500
501 }
502
503 }
504
505 return $errors;
506
507 }
508
509 /**
510 * Add login error message on top of the login form
511 *
512 * @since 2.5.0
513 */
514 public function add_failed_login_message( $message ) {
515
516 global $asenha_limit_login;
517
518 if ( isset( $_REQUEST['failed_login'] ) && $_REQUEST['failed_login'] == 'true' ) {
519
520 if ( ! $asenha_limit_login['within_lockout_period'] ) {
521
522 $message = '<div id="login_error"><b>Error:</b> Invalid username or incorrect password.</div>';
523
524 }
525
526 }
527
528 return $message;
529
530 }
531
532 /**
533 * Clear failed login attempts log after successful login
534 *
535 * @since 2.5.0
536 */
537 public function clear_failed_login_log() {
538
539 global $wpdb, $asenha_limit_login;
540 $table_name = $wpdb->prefix . 'asenha_failed_logins';
541
542 // Remove the DB log entry for the current IP address.
543
544 $where = array( 'ip_address' => $asenha_limit_login['ip_address'] );
545 $where_format = array( '%s' );
546
547 $wpdb->delete(
548 $table_name,
549 $where,
550 $where_format
551 );
552
553 }
554
555 /**
556 * If an author name is queried, decrypt it. Used by pre_get_posts action.
557 *
558 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/tags/4.0.2/inc/class-smart-user-slug-hider.php
559 * @since 2.1.0
560 */
561 function alter_author_query( $query ) {
562
563 // Check if it's a query for author data, and that 'author_name' is not empty
564 if ( $query->is_author() && $query->query_vars['author_name'] != '' ) {
565
566 // Check for character(s) representing a hexadecimal digit
567 if ( ctype_xdigit( $query->query_vars['author_name'] ) ) {
568
569 // Get user by the decrypted user ID
570 $user = get_user_by( 'id', $this->decrypt( $query->query_vars['author_name'] ) );
571
572 if ( $user ) {
573
574 $query->set( 'author_name', $user->user_nicename );
575
576 } else {
577
578 // No user found
579 $query->is_404 = true;
580 $query->is_author = false;
581 $query->is_archive = false;
582
583 }
584
585 } else {
586
587 // No hexadecimal digit detected in URL, i.e. someone is trying to access URL with original author slug
588 $query->is_404 = true;
589 $query->is_author = false;
590 $query->is_archive = false;
591
592 }
593
594 }
595
596 return;
597 }
598
599 /**
600 * Replace author slug in author link to encrypted value. Used by author_link filter.
601 *
602 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/tags/4.0.2/inc/class-smart-user-slug-hider.php
603 * @since 2.1.0
604 */
605 function alter_author_link( $link, $user_id, $author_slug ) {
606
607 $encrypted_author_slug = $this->encrypt( $user_id );
608
609 return str_replace ( '/' . $author_slug, '/' . $encrypted_author_slug, $link );
610
611 }
612
613 /**
614 * Replace author slug in REST API /users/ endpoint to encrypted value. Used by rest_prepare_user filter.
615 *
616 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/tags/4.0.2/inc/class-smart-user-slug-hider.php
617 * @since 2.1.0
618 */
619 function alter_json_users($response, $user, $request) {
620
621 $data = $response->get_data();
622 $data['slug'] = $this->encrypt($data['id']);
623 $response->set_data($data);
624
625 return $response;
626
627 }
628
629 /**
630 * Helper function to return an encrypted user ID, which will then be used to replace the author slug.
631 *
632 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/trunk/inc/class-smart-user-slug-hider.php
633 * @since 2.1.0
634 */
635 private function encrypt( $user_id ) {
636
637 // Returns encrypted encrypted author slug from user ID, e.g. encrypt user ID 3 to author slug 4e3062d8c8626a14
638 return bin2hex( openssl_encrypt( base_convert( $user_id, 10, 36 ), 'DES-EDE3', md5( sanitize_text_field( $_SERVER['SERVER_ADDR'] ) . ASENHA_URL ), OPENSSL_RAW_DATA ) );
639
640 }
641
642
643 /**
644 * Helper function to decrypt an (encrypted) author slug and returns the user ID
645 *
646 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/trunk/inc/class-smart-user-slug-hider.php
647 * @since 2.1.0
648 */
649 private function decrypt( $encrypted_author_slug ) {
650
651 // Returns user ID, e.g. decrypts author slug 4e3062d8c8626a14 into user ID 3
652 return base_convert( openssl_decrypt( pack('H*', $encrypted_author_slug), 'DES-EDE3', md5( sanitize_text_field( $_SERVER['SERVER_ADDR'] ) . ASENHA_URL ), OPENSSL_RAW_DATA ), 36, 10 );
653
654 }
655
656 }