PluginProbe ʕ •ᴥ•ʔ
Admin and Site Enhancements (ASE) / 3.0.0
Admin and Site Enhancements (ASE) v3.0.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 * Maybe allow login if not locked out. Should return WP_Error object if not allowed to login.
111 *
112 * @since 2.5.0
113 */
114 public function maybe_allow_login( $user_or_error, $username, $password ) {
115
116 global $wpdb, $asenha_limit_login;
117 $table_name = $wpdb->prefix . 'asenha_failed_logins';
118
119 // Maybe create table if it does not exist yet, e.g. upgraded from previous version of plugin, so, no activation methods are fired
120 $query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table_name ) );
121
122 if ( $wpdb->get_var( $query ) === $table_name ) {
123 // Table already exists, do nothing.
124 } else {
125 $activation = new Activation;
126 $activation->create_failed_logins_log_table();
127 }
128
129 // Get values from options needed to do various checks
130 $options = get_option( ASENHA_SLUG_U );
131 $login_fails_allowed = $options['login_fails_allowed'];
132 $login_lockout_maxcount = $options['login_lockout_maxcount'];
133 $change_login_url = $options['change_login_url'];
134 $custom_login_slug = $options['custom_login_slug'];
135
136 // Instantiate object to access common methods
137 $common_methods = new Common_Methods;
138
139 // Get user/visitor IP address
140 $ip_address = $common_methods->get_user_ip_address();
141
142 // Check if IP address has failed login attempts recorded in the DB log
143 $sql = $wpdb->prepare("SELECT * FROM `" . $table_name . "` Where `ip_address` = %s", $ip_address);
144 $result = $wpdb->get_results( $sql, ARRAY_A );
145
146 $result_count = count( $result );
147
148 if ( $result_count > 0 ) { // IP address has been recorded in the database.
149
150 // Custom Login URL is enabled
151 if ( array_key_exists( 'change_login_url', $options ) && $options['change_login_url'] ) {
152 $fail_count = $result[0]['fail_count'];
153 } else {
154 $fail_count = $result[0]['fail_count'] + 1;
155 }
156
157 $lockout_count = $result[0]['lockout_count'];
158 $last_fail_on = $result[0]['unixtime'];
159
160 } else {
161
162 $fail_count = 0;
163 $lockout_count = 0;
164 $last_fail_on = '';
165
166 }
167
168 // Initialize the global variable
169 $asenha_limit_login = array (
170 'ip_address' => $ip_address,
171 'request_uri' => sanitize_text_field( $_SERVER['REQUEST_URI'] ),
172 'ip_address_log' => $result,
173 'maybe_lockout' => false,
174 'extended_lockout' => false,
175 'within_lockout_period' => false,
176 'lockout_period' => 0,
177 'lockout_period_remaining' => 0,
178 'login_fails_allowed' => $login_fails_allowed,
179 'login_lockout_maxcount' => $login_lockout_maxcount,
180 // 'default_lockout_period' => 60, // 1 minutes in seconds
181 'default_lockout_period' => 60*15, // 15 minutes in seconds
182 // 'extended_lockout_period' => 3*60, // 3 minutes in seconds
183 'extended_lockout_period' => 24*60*60, // 24 hours in seconds
184 'change_login_url' => $change_login_url, // is custom login URL enabled?
185 'custom_login_slug' => $custom_login_slug,
186 );
187
188 if ( $result_count > 0 ) { // IP address has been recorded in the database.
189
190 // Failed attempts have been recorded and fulfills lockout condition
191 if ( ! empty( $fail_count ) && ( ( $fail_count ) % $login_fails_allowed == 0 ) ) {
192
193 $asenha_limit_login['maybe_lockout'] = true;
194
195 // Has reached max / gone beyond number of lockouts allowed?
196 if ( $lockout_count >= $login_lockout_maxcount ) {
197 $asenha_limit_login['extended_lockout'] = true;
198 $lockout_period = $asenha_limit_login['extended_lockout_period'];
199 } else {
200 $asenha_limit_login['extended_lockout'] = false;
201 $lockout_period = $asenha_limit_login['default_lockout_period'];
202 }
203
204 $asenha_limit_login['lockout_period'] = $lockout_period;
205
206 // User/visitor is still within the lockout period
207 if ( ( time() - $last_fail_on ) <= $asenha_limit_login['lockout_period'] ) {
208
209 $asenha_limit_login['within_lockout_period'] = true;
210 $asenha_limit_login['lockout_period_remaining'] = $asenha_limit_login['lockout_period'] - ( time() - $last_fail_on );
211
212 if ( $asenha_limit_login['lockout_period_remaining'] <= 60 ) {
213
214 // Get remaining lockout period in minutes and seconds
215 $lockout_period_remaining = $asenha_limit_login['lockout_period_remaining'] . ' seconds';
216
217 } elseif ( $asenha_limit_login['lockout_period_remaining'] <= 60*60 ) {
218
219 // Get remaining lockout period in minutes and seconds
220 $lockout_period_remaining = $common_methods->seconds_to_period( $asenha_limit_login['lockout_period_remaining'], 'to-minutes-seconds' );
221
222 } elseif ( $asenha_limit_login['lockout_period_remaining'] > 60*60 && $asenha_limit_login['lockout_period_remaining'] <= 24*60*60 ) {
223
224 // Get remaining lockout period in minutes and seconds
225 $lockout_period_remaining = $common_methods->seconds_to_period( $asenha_limit_login['lockout_period_remaining'], 'to-hours-minutes-seconds' );
226
227 } elseif ( $asenha_limit_login['lockout_period_remaining'] > 24*60*60 ) {
228
229 // Get remaining lockout period in minutes and seconds
230 $lockout_period_remaining = $common_methods->seconds_to_period( $asenha_limit_login['lockout_period_remaining'], 'to-days-hours-minutes-seconds' );
231
232 }
233
234 $error = new WP_Error( 'ip_address_blocked', '<b>WARNING:</b> You\'ve been locked out. You can login again in ' . $lockout_period_remaining . '.' );
235
236 // Prevent redirection loop
237 remove_action( 'wp_login_failed', [ $this, 'redirect_to_custom_login_url_on_login_fail' ] );
238
239 return $error;
240
241 } else { // User/visitor is no longer within the lockout period
242
243 $asenha_limit_login['within_lockout_period'] = false;
244
245 if ( $lockout_count == $login_lockout_maxcount ) {
246
247 // Remove the DB log entry for the current IP address. i.e. release from extended lockout
248
249 $where = array( 'ip_address' => $ip_address );
250 $where_format = array( '%s' );
251
252 // Delete existing data in the database
253 $wpdb->delete(
254 $table_name,
255 $where,
256 $where_format
257 );
258
259 }
260
261 return $user_or_error;
262
263 }
264
265 } else {
266
267 $asenha_limit_login['maybe_lockout'] = false;
268
269 return $user_or_error;
270
271 }
272
273 } else { // IP address has not been recorded in the database.
274
275 return $user_or_error;
276
277 }
278
279 }
280
281 /**
282 * Disable login form inputs via javascript
283 *
284 * @since 2.5.0
285 */
286 public function maybe_hide_login_form() {
287
288 global $asenha_limit_login;
289
290 if ( $asenha_limit_login['within_lockout_period'] ) {
291
292 // Hide logo, login form and the links below it
293 ?>
294 <style type="text/css">
295
296 body.login {
297 background:#f6d6d7;
298 }
299
300 #login h1,
301 #loginform,
302 #login #nav,
303 #backtoblog {
304 display: none;
305 }
306
307 @media screen and (max-height: 550px) {
308
309 #login {
310 padding: 80px 0 20px !important;
311 }
312
313 }
314
315 </style>
316 <?php
317 }
318
319 }
320
321 /**
322 * Log failed login attempts
323 *
324 * @since 2.5.0
325 */
326 public function log_failed_login( $username ) {
327
328 global $wpdb, $asenha_limit_login;
329 $table_name = $wpdb->prefix . 'asenha_failed_logins';
330
331 // Check if the IP address has been used in a failed login attempt before, i.e. has it been recorded in the database?
332 $sql = $wpdb->prepare( "SELECT * FROM `" . $table_name . "` WHERE `ip_address` = %s", $asenha_limit_login['ip_address'] );
333 $result = $wpdb->get_results( $sql, ARRAY_A );
334 $result_count = count( $result );
335
336 // Update logged info for the IP address in the global variable
337 $asenha_limit_login['ip_address_log'] = $result;
338
339 if ( $result_count == 0 ) { // IP address has not been recorded in the database.
340
341 $new_fail_count = 1;
342 $new_lockout_count = 0;
343
344 } else { // IP address has been recorded in the database.
345
346 $new_fail_count = $result[0]['fail_count'] + 1;
347 $new_lockout_count = floor( ( $result[0]['fail_count'] + 1 ) / $asenha_limit_login['login_fails_allowed'] );
348
349 }
350
351 // Get the URL where login failed, i.e. where brute force attack might be happening
352 // $login_url = ( ! empty( $_SERVER['HTTPS'] ) ? 'https://' : 'http://') . sanitize_text_field( $_SERVER['HTTP_HOST'] ) . sanitize_text_field( $_SERVER['REQUEST_URI'] );
353
354 // Time stamps
355 $unixtime = time();
356 if ( function_exists( 'wp_date' ) ) {
357 $datetime_wp = wp_date( 'Y-m-d H:i:s', $unixtime );
358 } else {
359 $datetime_wp = date_i18n( 'Y-m-d H:i:s', $unixtime );
360 }
361
362 $data = array(
363 'ip_address' => $asenha_limit_login['ip_address'],
364 'username' => $username,
365 'fail_count' => $new_fail_count,
366 'lockout_count' => $new_lockout_count,
367 'request_uri' => $asenha_limit_login['request_uri'],
368 'unixtime' => $unixtime,
369 'datetime_wp' => $datetime_wp,
370 'info' => '',
371 );
372
373 $data_format = array(
374 '%s', // string
375 '%s', // string
376 '%d', // integer
377 '%d', // integer
378 '%s', // string
379 '%d', // integer
380 '%s', // string
381 '%s', // string
382 );
383
384 if ( $result_count == 0 ) {
385
386 // Insert into the database
387 $result = $wpdb->insert(
388 $table_name,
389 $data,
390 $data_format
391 );
392
393 } else {
394
395 // $options = get_option( ASENHA_SLUG_U );
396 // $login_fails_allowed = $options['login_fails_allowed'];
397
398 $fail_count = $result[0]['fail_count'];
399 $lockout_count = $result[0]['lockout_count'];
400 $last_fail_on = $result[0]['unixtime'];
401
402 $where = array( 'ip_address' => $asenha_limit_login['ip_address'] );
403 $where_format = array( '%s' );
404
405 // Failed attempts have been recorded and fulfills lockout condition
406 if ( ! empty( $fail_count ) && ( $fail_count % $asenha_limit_login['login_fails_allowed'] == 0 ) ) {
407
408 // Has reached max / gone beyond number of lockouts allowed?
409 if ( $lockout_count >= $asenha_limit_login['login_lockout_maxcount'] ) {
410 $asenha_limit_login['extended_lockout'] = true;
411 $lockout_period = $asenha_limit_login['extended_lockout_period'];
412 } else {
413 $asenha_limit_login['extended_lockout'] = false;
414 $lockout_period = $asenha_limit_login['default_lockout_period'];
415 }
416
417 $asenha_limit_login['lockout_period'] = $lockout_period;
418
419 // User/visitor is still within the lockout period
420 if ( ( time() - $last_fail_on ) <= $asenha_limit_login['lockout_period'] ) {
421
422 // Do nothing
423
424 } else {
425
426 if ( $lockout_count < $asenha_limit_login['login_lockout_maxcount'] ) {
427
428 // Update existing data in the database
429 $wpdb->update(
430 $table_name,
431 $data,
432 $where,
433 $data_format,
434 $where_format
435 );
436
437 }
438
439 }
440
441 } else {
442
443 // Update existing data in the database
444 $wpdb->update(
445 $table_name,
446 $data,
447 $where,
448 $data_format,
449 $where_format
450 );
451
452 }
453
454 }
455
456 }
457
458 /**
459 * Handle login errors
460 *
461 * @link https://developer.wordpress.org/reference/classes/wp_error/#methods
462 * @since 2.5.0
463 */
464 public function login_error_handler( $errors, $redirect_to ) {
465
466 global $asenha_limit_login;
467
468 if ( is_wp_error( $errors ) ) {
469
470 $error_codes = $errors->get_error_codes();
471
472 foreach ( $error_codes as $error_code ) {
473
474 if ( $error_code == 'invalid_username' || $error_code == 'incorrect_password' ) {
475
476 // Remove default error messages that may give out valueable info to hackers
477
478 $errors->remove( 'invalid_username' ); // Outputs info that says username does not exist. May encourage login attempt with a different username instead.
479
480 $errors->remove( 'incorrect_password' ); // Outputs info that implies username exist. May encourage login attempt with a different password.
481
482 // Add a new error message that does not provide useful clues to hackers
483 $errors->add( 'invalid_username_or_incorrect_password', '<b>Error:</b> Invalid username or incorrect password.' );
484
485 // $errors->add( 'another_error_code', 'The error message.' );
486
487 }
488
489 }
490
491 }
492
493 return $errors;
494
495 }
496
497 /**
498 * Add login error message on top of the login form
499 *
500 * @since 2.5.0
501 */
502 public function add_failed_login_message( $message ) {
503
504 global $asenha_limit_login;
505
506 if ( isset( $_REQUEST['failed_login'] ) && $_REQUEST['failed_login'] == 'true' ) {
507
508 if ( ! $asenha_limit_login['within_lockout_period'] ) {
509
510 $message = '<div id="login_error"><b>Error:</b> Invalid username or incorrect password.</div>';
511
512 }
513
514 }
515
516 return $message;
517
518 }
519
520 /**
521 * Clear failed login attempts log after successful login
522 *
523 * @since 2.5.0
524 */
525 public function clear_failed_login_log() {
526
527 global $wpdb, $asenha_limit_login;
528 $table_name = $wpdb->prefix . 'asenha_failed_logins';
529
530 // Remove the DB log entry for the current IP address.
531
532 $where = array( 'ip_address' => $asenha_limit_login['ip_address'] );
533 $where_format = array( '%s' );
534
535 $wpdb->delete(
536 $table_name,
537 $where,
538 $where_format
539 );
540
541 }
542
543 /**
544 * If an author name is queried, decrypt it. Used by pre_get_posts action.
545 *
546 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/tags/4.0.2/inc/class-smart-user-slug-hider.php
547 * @since 2.1.0
548 */
549 function alter_author_query( $query ) {
550
551 // Check if it's a query for author data, and that 'author_name' is not empty
552 if ( $query->is_author() && $query->query_vars['author_name'] != '' ) {
553
554 // Check for character(s) representing a hexadecimal digit
555 if ( ctype_xdigit( $query->query_vars['author_name'] ) ) {
556
557 // Get user by the decrypted user ID
558 $user = get_user_by( 'id', $this->decrypt( $query->query_vars['author_name'] ) );
559
560 if ( $user ) {
561
562 $query->set( 'author_name', $user->user_nicename );
563
564 } else {
565
566 // No user found
567 $query->is_404 = true;
568 $query->is_author = false;
569 $query->is_archive = false;
570
571 }
572
573 } else {
574
575 // No hexadecimal digit detected in URL, i.e. someone is trying to access URL with original author slug
576 $query->is_404 = true;
577 $query->is_author = false;
578 $query->is_archive = false;
579
580 }
581
582 }
583
584 return;
585 }
586
587 /**
588 * Replace author slug in author link to encrypted value. Used by author_link filter.
589 *
590 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/tags/4.0.2/inc/class-smart-user-slug-hider.php
591 * @since 2.1.0
592 */
593 function alter_author_link( $link, $user_id, $author_slug ) {
594
595 $encrypted_author_slug = $this->encrypt( $user_id );
596
597 return str_replace ( '/' . $author_slug, '/' . $encrypted_author_slug, $link );
598
599 }
600
601 /**
602 * Replace author slug in REST API /users/ endpoint to encrypted value. Used by rest_prepare_user filter.
603 *
604 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/tags/4.0.2/inc/class-smart-user-slug-hider.php
605 * @since 2.1.0
606 */
607 function alter_json_users($response, $user, $request) {
608
609 $data = $response->get_data();
610 $data['slug'] = $this->encrypt($data['id']);
611 $response->set_data($data);
612
613 return $response;
614
615 }
616
617 /**
618 * Helper function to return an encrypted user ID, which will then be used to replace the author slug.
619 *
620 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/trunk/inc/class-smart-user-slug-hider.php
621 * @since 2.1.0
622 */
623 private function encrypt( $user_id ) {
624
625 // Returns encrypted encrypted author slug from user ID, e.g. encrypt user ID 3 to author slug 4e3062d8c8626a14
626 return bin2hex( openssl_encrypt( base_convert( $user_id, 10, 36 ), 'DES-EDE3', md5( sanitize_text_field( $_SERVER['SERVER_ADDR'] ) . ASENHA_URL ), OPENSSL_RAW_DATA ) );
627
628 }
629
630
631 /**
632 * Helper function to decrypt an (encrypted) author slug and returns the user ID
633 *
634 * @link https://plugins.trac.wordpress.org/browser/smart-user-slug-hider/trunk/inc/class-smart-user-slug-hider.php
635 * @since 2.1.0
636 */
637 private function decrypt( $encrypted_author_slug ) {
638
639 // Returns user ID, e.g. decrypts author slug 4e3062d8c8626a14 into user ID 3
640 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 );
641
642 }
643
644 /**
645 * Disable the XML-RPC component
646 *
647 * @since 2.2.0
648 */
649 public function maybe_disable_xmlrpc( $data ) {
650
651 http_response_code(403);
652 exit('You don\'t have permission to access this file.');
653
654 }
655
656 }