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