PluginProbe ʕ •ᴥ•ʔ
Admin and Site Enhancements (ASE) / 6.9.1
Admin and Site Enhancements (ASE) v6.9.1
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 2 years ago class-admin-interface.php 2 years ago class-common-methods.php 2 years ago class-content-management.php 2 years ago class-custom-code.php 2 years ago class-deactivation.php 2 years ago class-disable-components.php 2 years ago class-login-logout.php 2 years ago class-optimizations.php 2 years ago class-security.php 2 years ago class-settings-fields-render.php 2 years ago class-settings-sanitization.php 2 years ago class-settings-sections-fields.php 2 years ago class-utilities.php 2 years ago
class-security.php
595 lines
1 <?php
2
3 namespace ASENHA\Classes;
4
5 use WP_Error ;
6 /**
7 * Class related to Security features
8 *
9 * @since 1.4.0
10 */
11 class Security
12 {
13 /**
14 * Maybe allow login if not locked out. Should return WP_Error object if not allowed to login.
15 *
16 * @since 2.5.0
17 */
18 public function maybe_allow_login( $user_or_error, $username, $password )
19 {
20 global $wpdb, $asenha_limit_login ;
21 $table_name = $wpdb->prefix . 'asenha_failed_logins';
22 // Maybe create table if it does not exist yet, e.g. upgraded from previous version of plugin, so, no activation methods are fired
23 $query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table_name ) );
24
25 if ( $wpdb->get_var( $query ) === $table_name ) {
26 // Table already exists, do nothing.
27 } else {
28 $activation = new Activation();
29 $activation->create_failed_logins_log_table();
30 }
31
32 // Get values from options needed to do various checks
33 $options = get_option( ASENHA_SLUG_U, array() );
34 $login_fails_allowed = $options['login_fails_allowed'];
35 $login_lockout_maxcount = $options['login_lockout_maxcount'];
36 $ip_address_whitelist_raw = ( isset( $options['limit_login_attempts_ip_whitelist'] ) ? explode( PHP_EOL, $options['limit_login_attempts_ip_whitelist'] ) : array() );
37 $ip_address_whitelist = array();
38 if ( !empty($ip_address_whitelist_raw) ) {
39 foreach ( $ip_address_whitelist_raw as $ip_address ) {
40 $ip_address_whitelist[] = trim( $ip_address );
41 }
42 }
43 $change_login_url = $options['change_login_url'];
44 $custom_login_slug = $options['custom_login_slug'];
45 // Instantiate object to access common methods
46 $common_methods = new Common_Methods();
47 // Get user/visitor IP address
48 $ip_address = $common_methods->get_user_ip_address();
49
50 if ( !in_array( $ip_address, $ip_address_whitelist ) ) {
51 // IP is not whitelisted
52 // Check if IP address has failed login attempts recorded in the DB log
53 $sql = $wpdb->prepare( "SELECT * FROM `" . $table_name . "` Where `ip_address` = %s", $ip_address );
54 $result = $wpdb->get_results( $sql, ARRAY_A );
55 $result_count = count( $result );
56
57 if ( $result_count > 0 ) {
58 // IP address has been recorded in the database.
59 $fail_count = $result[0]['fail_count'];
60 $lockout_count = $result[0]['lockout_count'];
61 $last_fail_on = $result[0]['unixtime'];
62 } else {
63 $fail_count = 0;
64 $lockout_count = 0;
65 $last_fail_on = '';
66 }
67
68 } else {
69 // IP is whitelisted
70 $result = array();
71 $result_count = 0;
72 $fail_count = 0;
73 $lockout_count = 0;
74 $last_fail_on = '';
75 }
76
77 // Initialize the global variable
78 $asenha_limit_login = array(
79 'ip_address' => $ip_address,
80 'request_uri' => sanitize_text_field( $_SERVER['REQUEST_URI'] ),
81 'ip_address_log' => $result,
82 'fail_count' => $fail_count,
83 'lockout_count' => $lockout_count,
84 'maybe_lockout' => false,
85 'extended_lockout' => false,
86 'within_lockout_period' => false,
87 'lockout_period' => 0,
88 'lockout_period_remaining' => 0,
89 'login_fails_allowed' => $login_fails_allowed,
90 'login_lockout_maxcount' => $login_lockout_maxcount,
91 'default_lockout_period' => 60 * 15,
92 'extended_lockout_period' => 24 * 60 * 60,
93 'change_login_url' => $change_login_url,
94 'custom_login_slug' => $custom_login_slug,
95 );
96
97 if ( !in_array( $ip_address, $ip_address_whitelist ) ) {
98 // IP is not whitelisted
99
100 if ( $result_count > 0 ) {
101 // IP address has been recorded in the database.
102 // Failed attempts have been recorded and fulfills lockout condition
103
104 if ( !empty($fail_count) && $fail_count % $login_fails_allowed == 0 ) {
105 $asenha_limit_login['maybe_lockout'] = true;
106 // Has reached max / gone beyond number of lockouts allowed?
107
108 if ( $lockout_count >= $login_lockout_maxcount ) {
109 $asenha_limit_login['extended_lockout'] = true;
110 $lockout_period = $asenha_limit_login['extended_lockout_period'];
111 } else {
112 $asenha_limit_login['extended_lockout'] = false;
113 $lockout_period = $asenha_limit_login['default_lockout_period'];
114 }
115
116 $asenha_limit_login['lockout_period'] = $lockout_period;
117 // User/visitor is still within the lockout period
118
119 if ( time() - $last_fail_on <= $asenha_limit_login['lockout_period'] ) {
120 $asenha_limit_login['within_lockout_period'] = true;
121 $asenha_limit_login['lockout_period_remaining'] = $asenha_limit_login['lockout_period'] - (time() - $last_fail_on);
122
123 if ( $asenha_limit_login['lockout_period_remaining'] <= 60 ) {
124 // Get remaining lockout period in minutes and seconds
125 $lockout_period_remaining = $asenha_limit_login['lockout_period_remaining'] . ' seconds';
126 } elseif ( $asenha_limit_login['lockout_period_remaining'] <= 60 * 60 ) {
127 // Get remaining lockout period in minutes and seconds
128 $lockout_period_remaining = $common_methods->seconds_to_period( $asenha_limit_login['lockout_period_remaining'], 'to-minutes-seconds' );
129 } elseif ( $asenha_limit_login['lockout_period_remaining'] > 60 * 60 && $asenha_limit_login['lockout_period_remaining'] <= 24 * 60 * 60 ) {
130 // Get remaining lockout period in minutes and seconds
131 $lockout_period_remaining = $common_methods->seconds_to_period( $asenha_limit_login['lockout_period_remaining'], 'to-hours-minutes-seconds' );
132 } elseif ( $asenha_limit_login['lockout_period_remaining'] > 24 * 60 * 60 ) {
133 // Get remaining lockout period in minutes and seconds
134 $lockout_period_remaining = $common_methods->seconds_to_period( $asenha_limit_login['lockout_period_remaining'], 'to-days-hours-minutes-seconds' );
135 }
136
137 $error = new WP_Error( 'ip_address_blocked', '<b>WARNING:</b> You\'ve been locked out. You can login again in ' . $lockout_period_remaining . '.' );
138 return $error;
139 } else {
140 // User/visitor is no longer within the lockout period
141 $asenha_limit_login['within_lockout_period'] = false;
142
143 if ( $lockout_count == $login_lockout_maxcount ) {
144 // Remove the DB log entry for the current IP address. i.e. release from extended lockout
145 $where = array(
146 'ip_address' => $ip_address,
147 );
148 $where_format = array( '%s' );
149 // Delete existing data in the database
150 $wpdb->delete( $table_name, $where, $where_format );
151 }
152
153 return $user_or_error;
154 }
155
156 } else {
157 $asenha_limit_login['maybe_lockout'] = false;
158 return $user_or_error;
159 }
160
161 } else {
162 // IP address has not been recorded in the database.
163 return $user_or_error;
164 }
165
166 } else {
167 // IP is whitelisted
168 return $user_or_error;
169 }
170
171 }
172
173 /**
174 * Disable login form inputs via CSS
175 *
176 * @since 2.5.0
177 */
178 public function maybe_hide_login_form()
179 {
180 global $asenha_limit_login ;
181
182 if ( isset( $asenha_limit_login['within_lockout_period'] ) && $asenha_limit_login['within_lockout_period'] ) {
183 // Hide logo, login form and the links below it
184 ?>
185 <script>
186 document.addEventListener("DOMContentLoaded", function(event) {
187 var loginForm = document.getElementById("loginform");
188 loginForm.remove();
189 });
190 </script>
191 <style type="text/css">
192
193 body.login {
194 background:#f6d6d7;
195 }
196
197 #login h1,
198 #loginform,
199 #login #nav,
200 #backtoblog,
201 .language-switcher {
202 display: none;
203 }
204
205 @media screen and (max-height: 550px) {
206
207 #login {
208 padding: 80px 0 20px !important;
209 }
210
211 }
212
213 </style>
214 <?php
215 } else {
216 $options = get_option( ASENHA_SLUG_U, array() );
217 $login_fails_allowed = $options['login_fails_allowed'];
218 if ( isset( $asenha_limit_login['fail_count'] ) && ($login_fails_allowed - 1 == intval( $asenha_limit_login['fail_count'] ) || 2 * $login_fails_allowed - 1 == intval( $asenha_limit_login['fail_count'] ) || 3 * $login_fails_allowed - 1 == intval( $asenha_limit_login['fail_count'] ) || 4 * $login_fails_allowed - 1 == intval( $asenha_limit_login['fail_count'] ) || 5 * $login_fails_allowed - 1 == intval( $asenha_limit_login['fail_count'] ) || 6 * $login_fails_allowed - 1 == intval( $asenha_limit_login['fail_count'] )) ) {
219
220 if ( array_key_exists( 'change_login_url', $options ) && $options['change_login_url'] ) {
221 // Custom Login URL is enabled, e.g. /manage
222 // Do nothing
223 } else {
224 // Default login URL, i.e. /wp-login.php
225 // Reload the login page so we get the up-to-date data in $asenha_limit_login
226 ?>
227 <script>
228 window.location.reload();
229 </script>
230 <?php
231 }
232
233 }
234 }
235
236 }
237
238 /**
239 * Log failed login attempts
240 *
241 * @since 2.5.0
242 */
243 public function log_failed_login( $username )
244 {
245 global $wpdb, $asenha_limit_login ;
246 $table_name = $wpdb->prefix . 'asenha_failed_logins';
247 // Check if the IP address has been used in a failed login attempt before, i.e. has it been recorded in the database?
248 $sql = $wpdb->prepare( "SELECT * FROM `" . $table_name . "` WHERE `ip_address` = %s", $asenha_limit_login['ip_address'] );
249 $result = $wpdb->get_results( $sql, ARRAY_A );
250 $result_count = count( $result );
251 // Update logged info for the IP address in the global variable
252 $asenha_limit_login['ip_address_log'] = $result;
253
254 if ( $result_count == 0 ) {
255 // IP address has not been recorded in the database.
256 $new_fail_count = 1;
257 $new_lockout_count = 0;
258 } else {
259 // IP address has been recorded in the database.
260 $new_fail_count = $result[0]['fail_count'] + 1;
261 $new_lockout_count = floor( ($result[0]['fail_count'] + 1) / $asenha_limit_login['login_fails_allowed'] );
262 }
263
264 // Get the URL where login failed, i.e. where brute force attack might be happening
265 // $login_url = ( ! empty( $_SERVER['HTTPS'] ) ? 'https://' : 'http://') . sanitize_text_field( $_SERVER['HTTP_HOST'] ) . sanitize_text_field( $_SERVER['REQUEST_URI'] );
266 // Time stamps
267 $unixtime = time();
268
269 if ( function_exists( 'wp_date' ) ) {
270 $datetime_wp = wp_date( 'Y-m-d H:i:s', $unixtime );
271 } else {
272 $datetime_wp = date_i18n( 'Y-m-d H:i:s', $unixtime );
273 }
274
275 $data = array(
276 'ip_address' => $asenha_limit_login['ip_address'],
277 'username' => $username,
278 'fail_count' => $new_fail_count,
279 'lockout_count' => $new_lockout_count,
280 'request_uri' => $asenha_limit_login['request_uri'],
281 'unixtime' => $unixtime,
282 'datetime_wp' => $datetime_wp,
283 'info' => '',
284 );
285 $data_format = array(
286 '%s',
287 // string
288 '%s',
289 // string
290 '%d',
291 // integer
292 '%d',
293 // integer
294 '%s',
295 // string
296 '%d',
297 // integer
298 '%s',
299 // string
300 '%s',
301 );
302
303 if ( $result_count == 0 ) {
304 // Insert into the database
305 $result = $wpdb->insert( $table_name, $data, $data_format );
306 } else {
307 // $options = get_option( ASENHA_SLUG_U );
308 // $login_fails_allowed = $options['login_fails_allowed'];
309 $fail_count = $result[0]['fail_count'];
310 $lockout_count = $result[0]['lockout_count'];
311 $last_fail_on = $result[0]['unixtime'];
312 $where = array(
313 'ip_address' => $asenha_limit_login['ip_address'],
314 );
315 $where_format = array( '%s' );
316 // Failed attempts have been recorded and fulfills lockout condition
317
318 if ( !empty($fail_count) && $fail_count % $asenha_limit_login['login_fails_allowed'] == 0 ) {
319 // Has reached max / gone beyond number of lockouts allowed?
320
321 if ( $lockout_count >= $asenha_limit_login['login_lockout_maxcount'] ) {
322 $asenha_limit_login['extended_lockout'] = true;
323 $lockout_period = $asenha_limit_login['extended_lockout_period'];
324 } else {
325 $asenha_limit_login['extended_lockout'] = false;
326 $lockout_period = $asenha_limit_login['default_lockout_period'];
327 }
328
329 $asenha_limit_login['lockout_period'] = $lockout_period;
330 // User/visitor is still within the lockout period
331
332 if ( time() - $last_fail_on <= $asenha_limit_login['lockout_period'] ) {
333 // Do nothing
334 } else {
335 if ( $lockout_count < $asenha_limit_login['login_lockout_maxcount'] ) {
336 // Update existing data in the database
337 $wpdb->update(
338 $table_name,
339 $data,
340 $where,
341 $data_format,
342 $where_format
343 );
344 }
345 }
346
347 } else {
348 // Update existing data in the database
349 $wpdb->update(
350 $table_name,
351 $data,
352 $where,
353 $data_format,
354 $where_format
355 );
356 }
357
358 }
359
360 }
361
362 /**
363 * Handle login errors
364 *
365 * @link https://developer.wordpress.org/reference/classes/wp_error/#methods
366 * @since 2.5.0
367 */
368 public function login_error_handler( $errors, $redirect_to )
369 {
370 global $asenha_limit_login ;
371
372 if ( is_wp_error( $errors ) ) {
373 $error_codes = $errors->get_error_codes();
374 foreach ( $error_codes as $error_code ) {
375
376 if ( $error_code == 'invalid_username' || $error_code == 'incorrect_password' ) {
377 // Remove default error messages that may give out valueable info to hackers
378 $errors->remove( 'invalid_username' );
379 // Outputs info that says username does not exist. May encourage login attempt with a different username instead.
380 $errors->remove( 'incorrect_password' );
381 // Outputs info that implies username exist. May encourage login attempt with a different password.
382 // Add a new error message that does not provide useful clues to hackers
383 $errors->add( 'invalid_username_or_incorrect_password', '<b>Error:</b> Invalid username/email or incorrect password.' );
384 // $errors->add( 'another_error_code', 'The error message.' );
385 }
386
387 }
388 }
389
390 return $errors;
391 }
392
393 /**
394 * Add login error message on top of the login form
395 *
396 * @since 2.5.0
397 */
398 public function add_failed_login_message( $message )
399 {
400 global $asenha_limit_login ;
401 if ( isset( $_REQUEST['failed_login'] ) && $_REQUEST['failed_login'] == 'true' ) {
402 if ( !is_null( $asenha_limit_login ) && isset( $asenha_limit_login['within_lockout_period'] ) && !$asenha_limit_login['within_lockout_period'] ) {
403 $message = '<div id="login_error" class="notice notice-error"><b>Error:</b> Invalid username/email or incorrect password.</div>';
404 }
405 }
406 return $message;
407 }
408
409 /**
410 * Clear failed login attempts log after successful login
411 *
412 * @since 2.5.0
413 */
414 public function clear_failed_login_log()
415 {
416 global $wpdb, $asenha_limit_login ;
417 $table_name = $wpdb->prefix . 'asenha_failed_logins';
418 $ip_address = ( isset( $asenha_limit_login['ip_address'] ) ? $asenha_limit_login['ip_address'] : '' );
419 // Remove the DB log entry for the current IP address.
420 $where = array(
421 'ip_address' => $ip_address,
422 );
423 $where_format = array( '%s' );
424 $wpdb->delete( $table_name, $where, $where_format );
425 }
426
427 /**
428 * Obfuscate email address on the frontend using antispambot() native WP function
429 *
430 * @link: https://gist.github.com/eclarrrk/349360b52e8822b69cb6fc499722520f
431 * @since 5.5.0
432 */
433 public function obfuscate_string( $atts )
434 {
435 $atts = shortcode_atts( array(
436 'email' => '',
437 'subject' => '',
438 'display' => 'newline',
439 'link' => 'no',
440 'class' => '',
441 ), $atts );
442 $email = $atts['email'];
443 if ( !is_email( $email ) ) {
444 return;
445 }
446 // Reverse email address characters if not in Firefox, which has bug related to unicode-bidi CSS property
447 $http_user_agent = ( isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : 'generic' );
448
449 if ( false !== stripos( sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ), 'firefox' ) ) {
450 // Do nothing. Do not reverse characters.
451 $email_reversed = $email;
452 $email_rev_parts = explode( '@', $email_reversed );
453 $email_rev_parts = array( $email_rev_parts[0], $email_rev_parts[1] );
454 $css_bidi_styles = '';
455 } else {
456 $email_reversed = strrev( $email );
457 $email_rev_parts = explode( '@', $email_reversed );
458 $css_bidi_styles = 'unicode-bidi:bidi-override;';
459 }
460
461 $display = $atts['display'];
462
463 if ( 'newline' == $display ) {
464 $display_css = 'display:flex;justify-content:flex-end;';
465 } elseif ( 'inline' == $display ) {
466 $display_css = 'display:inline;';
467 }
468
469 $subject = $atts['subject'];
470 if ( !empty($subject) ) {
471 $subject = '?subject=' . $subject;
472 }
473 $link = $atts['link'];
474 $class = $atts['class'];
475 return '<div style="display:inline;' . esc_attr( $css_bidi_styles ) . ';direction:rtl;" class="' . esc_attr( $class ) . '">' . esc_html( $email_rev_parts[0] ) . '<span style="display:none;">obfsctd</span>&#64;' . esc_html( $email_rev_parts[1] ) . '</div>';
476 }
477
478 /**
479 * If an author name is queried, decrypt it. Used by pre_get_posts action.
480 *
481 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/tags/4.0.2/inc/class-smart-user-slug-hider.php
482 * @since 2.1.0
483 */
484 function alter_author_query( $query )
485 {
486 // Check if it's a query for author data, and that 'author_name' is not empty
487 if ( $query->is_author() && $query->query_vars['author_name'] != '' ) {
488 // Check for character(s) representing a hexadecimal digit
489
490 if ( ctype_xdigit( $query->query_vars['author_name'] ) ) {
491 // Get user by the decrypted user ID
492 $user = get_user_by( 'id', $this->decrypt( $query->query_vars['author_name'] ) );
493
494 if ( $user ) {
495 $query->set( 'author_name', $user->user_nicename );
496 } else {
497 // No user found
498 $query->is_404 = true;
499 $query->is_author = false;
500 $query->is_archive = false;
501 }
502
503 } else {
504 // No hexadecimal digit detected in URL, i.e. someone is trying to access URL with original author slug
505 $query->is_404 = true;
506 $query->is_author = false;
507 $query->is_archive = false;
508 }
509
510 }
511 return;
512 }
513
514 /**
515 * Replace author slug in author link to encrypted value. Used by author_link filter.
516 *
517 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/tags/4.0.2/inc/class-smart-user-slug-hider.php
518 * @since 2.1.0
519 */
520 function alter_author_link( $link, $user_id, $author_slug )
521 {
522 $encrypted_author_slug = $this->encrypt( $user_id );
523 return str_replace( '/' . $author_slug, '/' . $encrypted_author_slug, $link );
524 }
525
526 /**
527 * Replace author slug in REST API /users/ endpoint to encrypted value. Used by rest_prepare_user filter.
528 *
529 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/tags/4.0.2/inc/class-smart-user-slug-hider.php
530 * @since 2.1.0
531 */
532 function alter_json_users( $response, $user, $request )
533 {
534 $data = $response->get_data();
535 $data['slug'] = $this->encrypt( $data['id'] );
536 $response->set_data( $data );
537 return $response;
538 }
539
540 /**
541 * Helper function to return an encrypted user ID, which will then be used to replace the author slug.
542 *
543 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/trunk/inc/class-smart-user-slug-hider.php
544 * @since 2.1.0
545 */
546 private function encrypt( $user_id )
547 {
548 // Returns encrypted encrypted author slug from user ID, e.g. encrypt user ID 3 to author slug 4e3062d8c8626a14
549 return bin2hex( openssl_encrypt(
550 base_convert( $user_id, 10, 36 ),
551 'DES-EDE3',
552 md5( ASENHA_URL ),
553 OPENSSL_RAW_DATA
554 ) );
555 }
556
557 /**
558 * Helper function to decrypt an (encrypted) author slug and returns the user ID
559 *
560 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/trunk/inc/class-smart-user-slug-hider.php
561 * @since 2.1.0
562 */
563 private function decrypt( $encrypted_author_slug )
564 {
565 // Returns user ID, e.g. decrypts author slug 4e3062d8c8626a14 into user ID 3
566 return base_convert( openssl_decrypt(
567 pack( 'H*', $encrypted_author_slug ),
568 'DES-EDE3',
569 md5( ASENHA_URL ),
570 OPENSSL_RAW_DATA
571 ), 36, 10 );
572 }
573
574 /**
575 * Remove XML RPC link in head
576 *
577 * @since 6.2.2
578 */
579 public function remove_xmlrpc_link()
580 {
581 remove_action( 'wp_head', 'rsd_link' );
582 }
583
584 /**
585 * Disable the XML-RPC component
586 *
587 * @since 2.2.0
588 */
589 public function maybe_disable_xmlrpc( $data )
590 {
591 http_response_code( 403 );
592 exit( 'You don\'t have permission to access this file.' );
593 }
594
595 }