iThemes Security (formerly Better WP Security) - Version 6.8.1

Version Description

  • Enhancement: Display user lockouts in Lockout Sidebar.
  • Bug Fix: Load translations on the plugins_loaded hook.
  • Bug Fix: Fixed method that could be used to discover hidden login slug on some sites.
  • Bug Fix: Fixed issue that could prevent Sync from loading Malware Scan results if a scan previously failed.
  • Bug Fix: Update to the REST API "Restricted Access" feature to protect against methods to work around the restricted access.
  • Bug Fix: Prevent login page being hidden when following the "Confirm Email Address" notification URL.
  • Bug Fix: Hide Backend notifications not being properly sent when first enabled.
Download this release

Release Info

Developer chrisjean
Plugin Icon 128x128 iThemes Security (formerly Better WP Security)
Version 6.8.1
Comparing to
See all releases

Code changes from version 6.8.0 to 6.8.1

better-wp-security.php CHANGED
@@ -6,16 +6,27 @@
6
  * Description: Take the guesswork out of WordPress security. iThemes Security offers 30+ ways to lock down WordPress in an easy-to-use WordPress security plugin.
7
  * Author: iThemes
8
  * Author URI: https://ithemes.com
9
- * Version: 6.8.0
10
  * Text Domain: better-wp-security
11
  * Network: True
12
  * License: GPLv2
13
  */
14
 
 
15
 
16
- $locale = apply_filters( 'plugin_locale', get_locale(), 'better-wp-security' );
17
- load_textdomain( 'better-wp-security', WP_LANG_DIR . "/plugins/better-wp-security/better-wp-security-$locale.mo" );
18
- load_plugin_textdomain( 'better-wp-security' );
 
 
 
 
 
 
 
 
 
 
19
 
20
  if ( isset( $itsec_dir ) || class_exists( 'ITSEC_Core' ) ) {
21
  include( dirname( __FILE__ ) . '/core/show-multiple-version-notice.php' );
@@ -31,4 +42,4 @@ if ( is_admin() ) {
31
 
32
  require( "$itsec_dir/core/core.php" );
33
  $itsec_core = ITSEC_Core::get_instance();
34
- $itsec_core->init( __FILE__, esc_html__( 'iThemes Security', 'better-wp-security' ) );
6
  * Description: Take the guesswork out of WordPress security. iThemes Security offers 30+ ways to lock down WordPress in an easy-to-use WordPress security plugin.
7
  * Author: iThemes
8
  * Author URI: https://ithemes.com
9
+ * Version: 6.8.1
10
  * Text Domain: better-wp-security
11
  * Network: True
12
  * License: GPLv2
13
  */
14
 
15
+ function itsec_load_textdomain() {
16
 
17
+ if ( function_exists( 'get_user_locale' ) && is_admin() ) {
18
+ $locale = get_user_locale();
19
+ } else {
20
+ $locale = get_locale();
21
+ }
22
+
23
+ $locale = apply_filters( 'plugin_locale', $locale, 'better-wp-security' );
24
+
25
+ load_textdomain( 'better-wp-security', WP_LANG_DIR . "/plugins/better-wp-security/better-wp-security-$locale.mo" );
26
+ load_plugin_textdomain( 'better-wp-security' );
27
+ }
28
+
29
+ add_action( 'plugins_loaded', 'itsec_load_textdomain' );
30
 
31
  if ( isset( $itsec_dir ) || class_exists( 'ITSEC_Core' ) ) {
32
  include( dirname( __FILE__ ) . '/core/show-multiple-version-notice.php' );
42
 
43
  require( "$itsec_dir/core/core.php" );
44
  $itsec_core = ITSEC_Core::get_instance();
45
+ $itsec_core->init( __FILE__, 'iThemes Security' );
core/core.php CHANGED
@@ -106,7 +106,6 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
106
  register_deactivation_hook( $this->plugin_file, array( 'ITSEC_Core', 'handle_deactivation' ) );
107
  register_uninstall_hook( $this->plugin_file, array( 'ITSEC_Core', 'handle_uninstall' ) );
108
 
109
-
110
  require( $this->plugin_dir . 'core/modules.php' );
111
  add_action( 'itsec-register-modules', array( $this, 'register_modules' ) );
112
  ITSEC_Modules::init_modules();
@@ -123,8 +122,6 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
123
  require( $this->plugin_dir . 'core/lib/class-itsec-scheduler.php' );
124
  require( $this->plugin_dir . 'core/lib/class-itsec-job.php' );
125
 
126
- $this->setup_scheduler();
127
-
128
  $this->itsec_files = ITSEC_Files::get_instance();
129
  $this->itsec_notify = new ITSEC_Notify();
130
  $itsec_logger = new ITSEC_Logger();
@@ -132,10 +129,7 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
132
  $itsec_lockout->run();
133
 
134
  // Handle upgrade if needed.
135
- if ( ITSEC_Modules::get_setting( 'global', 'build' ) < $this->plugin_build ) {
136
- add_action( 'plugins_loaded', array( $this, 'handle_upgrade' ), -100 );
137
- }
138
-
139
 
140
  if ( is_admin() ) {
141
  require( $this->plugin_dir . 'core/admin-pages/init.php' );
@@ -158,6 +152,7 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
158
  * Perform initialization that requires the plugins_loaded hook to be fired.
159
  */
160
  public function continue_init() {
 
161
  ITSEC_Modules::run_active_modules();
162
 
163
  //Admin bar links
@@ -181,6 +176,10 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
181
 
182
  private function setup_scheduler() {
183
 
 
 
 
 
184
  $choices = array(
185
  'ITSEC_Scheduler_Cron' => $this->plugin_dir . 'core/lib/class-itsec-scheduler-cron.php',
186
  'ITSEC_Scheduler_Page_Load' => $this->plugin_dir . 'core/lib/class-itsec-scheduler-page-load.php',
@@ -251,7 +250,14 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
251
  * @return ITSEC_Scheduler
252
  */
253
  public static function get_scheduler() {
254
- return self::get_instance()->scheduler;
 
 
 
 
 
 
 
255
  }
256
 
257
  /**
@@ -439,6 +445,11 @@ if ( ! class_exists( 'ITSEC_Core' ) ) {
439
  * @param int|bool $build The version of the data storage format. Pass false to default to the current version.
440
  */
441
  public function handle_upgrade( $build = false ) {
 
 
 
 
 
442
  $this->doing_data_upgrade = true;
443
 
444
  require_once( self::get_core_dir() . '/setup.php' );
106
  register_deactivation_hook( $this->plugin_file, array( 'ITSEC_Core', 'handle_deactivation' ) );
107
  register_uninstall_hook( $this->plugin_file, array( 'ITSEC_Core', 'handle_uninstall' ) );
108
 
 
109
  require( $this->plugin_dir . 'core/modules.php' );
110
  add_action( 'itsec-register-modules', array( $this, 'register_modules' ) );
111
  ITSEC_Modules::init_modules();
122
  require( $this->plugin_dir . 'core/lib/class-itsec-scheduler.php' );
123
  require( $this->plugin_dir . 'core/lib/class-itsec-job.php' );
124
 
 
 
125
  $this->itsec_files = ITSEC_Files::get_instance();
126
  $this->itsec_notify = new ITSEC_Notify();
127
  $itsec_logger = new ITSEC_Logger();
129
  $itsec_lockout->run();
130
 
131
  // Handle upgrade if needed.
132
+ add_action( 'plugins_loaded', array( $this, 'handle_upgrade' ), -100, 0 );
 
 
 
133
 
134
  if ( is_admin() ) {
135
  require( $this->plugin_dir . 'core/admin-pages/init.php' );
152
  * Perform initialization that requires the plugins_loaded hook to be fired.
153
  */
154
  public function continue_init() {
155
+ $this->setup_scheduler();
156
  ITSEC_Modules::run_active_modules();
157
 
158
  //Admin bar links
176
 
177
  private function setup_scheduler() {
178
 
179
+ if ( $this->scheduler ) {
180
+ return;
181
+ }
182
+
183
  $choices = array(
184
  'ITSEC_Scheduler_Cron' => $this->plugin_dir . 'core/lib/class-itsec-scheduler-cron.php',
185
  'ITSEC_Scheduler_Page_Load' => $this->plugin_dir . 'core/lib/class-itsec-scheduler-page-load.php',
250
  * @return ITSEC_Scheduler
251
  */
252
  public static function get_scheduler() {
253
+
254
+ $self = self::get_instance();
255
+
256
+ if ( ! $self->scheduler ) {
257
+ $self->setup_scheduler();
258
+ }
259
+
260
+ return $self->scheduler;
261
  }
262
 
263
  /**
445
  * @param int|bool $build The version of the data storage format. Pass false to default to the current version.
446
  */
447
  public function handle_upgrade( $build = false ) {
448
+
449
+ if ( func_num_args() === 0 && ITSEC_Modules::get_setting( 'global', 'build' ) >= $this->plugin_build ) {
450
+ return;
451
+ }
452
+
453
  $this->doing_data_upgrade = true;
454
 
455
  require_once( self::get_core_dir() . '/setup.php' );
core/history.txt CHANGED
@@ -621,4 +621,12 @@
621
  4.0.3 - 2017-01-04 - Chris Jean & Timothy Jacobs
622
  Bug Fix: Fix scheduling retries for Malware Scans on sites that don't fully support WordPress's cron system.
623
  Bug Fix: Reactivating Away Mode now replaces the active file if you had previously removed it.
624
- Bug Fix: Ensure lockouts take effect immediately, even on systems where changes to server configuration files do not take effect immediately.
 
 
 
 
 
 
 
 
621
  4.0.3 - 2017-01-04 - Chris Jean & Timothy Jacobs
622
  Bug Fix: Fix scheduling retries for Malware Scans on sites that don't fully support WordPress's cron system.
623
  Bug Fix: Reactivating Away Mode now replaces the active file if you had previously removed it.
624
+ Bug Fix: Ensure lockouts take effect immediately, even on systems where changes to server configuration files do not take effect immediately.
625
+ 4.0.4 - 2017-01-29 - Chris Jean & Timothy Jacobs
626
+ Enhancement: Display user lockouts in Lockout Sidebar.
627
+ Bug Fix: Load translations on the plugins_loaded hook.
628
+ Bug Fix: Fixed method that could be used to discover hidden login slug on some sites.
629
+ Bug Fix: Fixed issue that could prevent Sync from loading Malware Scan results if a scan previously failed.
630
+ Bug Fix: Update to the REST API "Restricted Access" feature to protect against methods to work around the restricted access.
631
+ Bug Fix: Prevent login page being hidden when following the "Confirm Email Address" notification URL.
632
+ Bug Fix: Hide Backend notifications not being properly sent when first enabled.
core/lib/class-itsec-scheduler.php CHANGED
@@ -44,6 +44,18 @@ abstract class ITSEC_Scheduler {
44
  */
45
  abstract public function schedule_once( $at, $id, $data = array() );
46
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  /**
48
  * Is a recurring event scheduled.
49
  *
44
  */
45
  abstract public function schedule_once( $at, $id, $data = array() );
46
 
47
+ /**
48
+ * Schedule a single event to run soon.
49
+ *
50
+ * @param string $id
51
+ * @param array $data
52
+ *
53
+ * @return bool
54
+ */
55
+ public function schedule_soon( $id, $data = array() ) {
56
+ return $this->schedule_once( ITSEC_Core::get_current_time_gmt() + 60 * mt_rand( 1, 10 ), $id, $data );
57
+ }
58
+
59
  /**
60
  * Is a recurring event scheduled.
61
  *
core/lockout.php CHANGED
@@ -150,7 +150,7 @@ final class ITSEC_Lockout {
150
  * @return void
151
  */
152
  public function check_lockout( $user = false, $username = false, $type = '' ) {
153
- global $wpdb, $itsec_globals;
154
 
155
  $wpdb->hide_errors(); //Hide database errors in case the tables aren't there
156
 
@@ -564,7 +564,7 @@ final class ITSEC_Lockout {
564
  *
565
  * @since 4.0
566
  *
567
- * @param string $type 'all', 'host', or 'user'
568
  * @param array $args Additional arguments.
569
  *
570
  * @return array all lockouts in the system
@@ -1106,7 +1106,7 @@ final class ITSEC_Lockout {
1106
 
1107
  $lockout = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE lockout_id = %d;", $id ), ARRAY_A );
1108
 
1109
- if ( is_array( $lockout ) && sizeof( $lockout ) >= 1 ) {
1110
 
1111
  $success = $wpdb->update(
1112
  $wpdb->base_prefix . 'itsec_lockouts',
@@ -1120,56 +1120,10 @@ final class ITSEC_Lockout {
1120
 
1121
  return $success === false ? false : true;
1122
 
1123
- } else {
1124
-
1125
- return false;
1126
-
1127
- }
1128
-
1129
- } elseif ( isset( $_POST['itsec_release_lockout'] ) && $_POST['itsec_release_lockout'] == 'true' ) {
1130
-
1131
- if ( ! wp_verify_nonce( $_POST['wp_nonce'], 'itsec_release_lockout' ) ) {
1132
- die( __( 'Security error!', 'better-wp-security' ) );
1133
- }
1134
-
1135
- $type = 'updated';
1136
- $message = __( 'The selected lockouts have been cleared.', 'better-wp-security' );
1137
-
1138
- foreach ( $_POST as $key => $value ) {
1139
-
1140
- if ( strstr( $key, "lo_" ) ) { //see if it's a lockout to avoid processing extra post fields
1141
-
1142
- $wpdb->update(
1143
- $wpdb->base_prefix . 'itsec_lockouts',
1144
- array(
1145
- 'lockout_active' => 0,
1146
- ),
1147
- array(
1148
- 'lockout_id' => (int) $value,
1149
- )
1150
- );
1151
-
1152
- }
1153
-
1154
  }
1155
-
1156
- ITSEC_Lib::clear_caches();
1157
-
1158
- if ( is_multisite() ) {
1159
-
1160
- $error_handler = new WP_Error();
1161
-
1162
- $error_handler->add( $type, $message );
1163
-
1164
- ITSEC_Lib::show_error_message( $error_handler );
1165
- } else {
1166
-
1167
- add_settings_error( 'itsec', esc_attr( 'settings_updated' ), $message, $type );
1168
-
1169
- }
1170
-
1171
  }
1172
 
 
1173
  }
1174
 
1175
  /**
@@ -1294,8 +1248,6 @@ final class ITSEC_Lockout {
1294
  */
1295
  public function set_lockout_error() {
1296
 
1297
- global $itsec_globals;
1298
-
1299
  //check to see if it's the logout screen
1300
  if ( isset( $_GET['itsec'] ) && $_GET['itsec'] == true ) {
1301
  return '<div id="login_error">' . ITSEC_Modules::get_setting( 'global', 'user_lockout_message' ) . '</div>' . PHP_EOL;
150
  * @return void
151
  */
152
  public function check_lockout( $user = false, $username = false, $type = '' ) {
153
+ global $wpdb;
154
 
155
  $wpdb->hide_errors(); //Hide database errors in case the tables aren't there
156
 
564
  *
565
  * @since 4.0
566
  *
567
+ * @param string $type 'all', 'host', 'user' or 'username'.
568
  * @param array $args Additional arguments.
569
  *
570
  * @return array all lockouts in the system
1106
 
1107
  $lockout = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$wpdb->base_prefix}itsec_lockouts` WHERE lockout_id = %d;", $id ), ARRAY_A );
1108
 
1109
+ if ( is_array( $lockout ) && count( $lockout ) >= 1 ) {
1110
 
1111
  $success = $wpdb->update(
1112
  $wpdb->base_prefix . 'itsec_lockouts',
1120
 
1121
  return $success === false ? false : true;
1122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1123
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1124
  }
1125
 
1126
+ return false;
1127
  }
1128
 
1129
  /**
1248
  */
1249
  public function set_lockout_error() {
1250
 
 
 
1251
  //check to see if it's the logout screen
1252
  if ( isset( $_GET['itsec'] ) && $_GET['itsec'] == true ) {
1253
  return '<div id="login_error">' . ITSEC_Modules::get_setting( 'global', 'user_lockout_message' ) . '</div>' . PHP_EOL;
core/modules/hide-backend/class-itsec-hide-backend.php CHANGED
@@ -24,9 +24,11 @@ class ITSEC_Hide_Backend {
24
 
25
  add_action( 'init', array( $this, 'handle_specific_page_requests' ), 1000 );
26
  add_action( 'signup_hidden_fields', array( $this, 'add_token_to_registration_form' ) );
 
27
 
28
  add_filter( 'site_url', array( $this, 'filter_generated_url' ), 100, 2 );
29
  add_filter( 'network_site_url', array( $this, 'filter_generated_url' ), 100, 2 );
 
30
  add_filter( 'wp_redirect', array( $this, 'filter_redirect' ) );
31
  add_filter( 'comment_moderation_text', array( $this, 'filter_comment_moderation_text' ) );
32
  add_filter( 'itsec_notify_admin_page_url', array( $this, 'filter_notify_admin_page_urls' ) );
@@ -48,7 +50,7 @@ class ITSEC_Hide_Backend {
48
  */
49
  public function filter_comment_moderation_text( $text ) {
50
  if ( $this->disable_filters ) {
51
- return $location;
52
  }
53
 
54
  // The email is plain text and the links are at the end of lines, so a lazy match can be used.
@@ -86,10 +88,7 @@ class ITSEC_Hide_Backend {
86
  $this->handle_canonical_login_page();
87
  } else if ( 'wp-admin' === $request_path || 'wp-admin/' === substr( $request_path, 0, 9 ) ) {
88
  $this->handle_wp_admin_page();
89
- } else if ( 'wp-signup.php' === $this->settings['register'] ) {
90
- // Only "hide" the signup page if a different slug was chosen for it.
91
- return;
92
- } else if ( $request_path === $this->settings['register'] ) {
93
  $this->handle_registration_alias();
94
  } else if ( 'wp-signup.php' === $request_path ) {
95
  $this->handle_canonical_signup_page();
@@ -143,6 +142,11 @@ class ITSEC_Hide_Backend {
143
  * @return void
144
  */
145
  private function handle_registration_alias() {
 
 
 
 
 
146
  if ( get_option( 'users_can_register' ) ) {
147
  if ( is_multisite() ) {
148
  $this->do_redirect_with_token( 'register', 'wp-signup.php' );
@@ -248,12 +252,15 @@ class ITSEC_Hide_Backend {
248
  list( $clean_path ) = explode( '?', $path );
249
 
250
  if ( 'wp-login.php' === $clean_path && 'wp-login.php' !== $this->settings['slug'] ) {
 
 
 
251
  if ( false !== strpos( $path, 'action=postpass' ) ) {
252
  // No special handling is needed for a password-protected post.
253
  return $url;
254
  } else if ( false !== strpos( $path, 'action=register' ) ) {
255
  $url = $this->add_token_to_url( $url, 'register' );
256
- } else {
257
  $url = $this->add_token_to_url( $url, 'login' );
258
  }
259
  } else if ( 'wp-signup.php' === $clean_path && 'wp-signup.php' !== $this->settings['register'] ) {
@@ -263,6 +270,23 @@ class ITSEC_Hide_Backend {
263
  return $url;
264
  }
265
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  /**
267
  * Filter redirection URLs to login and signup pages to include the access token query arg.
268
  *
@@ -320,6 +344,18 @@ class ITSEC_Hide_Backend {
320
  }
321
  }
322
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  /**
324
  * Register the New Login URL notification.
325
  *
@@ -409,4 +445,18 @@ class ITSEC_Hide_Backend {
409
 
410
  return $this->settings['slug'];
411
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  }
24
 
25
  add_action( 'init', array( $this, 'handle_specific_page_requests' ), 1000 );
26
  add_action( 'signup_hidden_fields', array( $this, 'add_token_to_registration_form' ) );
27
+ add_action( 'login_enqueue_scripts', array( $this, 'login_enqueue' ) );
28
 
29
  add_filter( 'site_url', array( $this, 'filter_generated_url' ), 100, 2 );
30
  add_filter( 'network_site_url', array( $this, 'filter_generated_url' ), 100, 2 );
31
+ add_filter( 'admin_url', array( $this, 'filter_admin_url' ), 100, 2 );
32
  add_filter( 'wp_redirect', array( $this, 'filter_redirect' ) );
33
  add_filter( 'comment_moderation_text', array( $this, 'filter_comment_moderation_text' ) );
34
  add_filter( 'itsec_notify_admin_page_url', array( $this, 'filter_notify_admin_page_urls' ) );
50
  */
51
  public function filter_comment_moderation_text( $text ) {
52
  if ( $this->disable_filters ) {
53
+ return $text;
54
  }
55
 
56
  // The email is plain text and the links are at the end of lines, so a lazy match can be used.
88
  $this->handle_canonical_login_page();
89
  } else if ( 'wp-admin' === $request_path || 'wp-admin/' === substr( $request_path, 0, 9 ) ) {
90
  $this->handle_wp_admin_page();
91
+ } else if ( $request_path === $this->settings['register'] && $this->allow_access_to_wp_signup() ) {
 
 
 
92
  $this->handle_registration_alias();
93
  } else if ( 'wp-signup.php' === $request_path ) {
94
  $this->handle_canonical_signup_page();
142
  * @return void
143
  */
144
  private function handle_registration_alias() {
145
+
146
+ if ( 'wp-signup.php' === $this->settings['register'] ) {
147
+ return;
148
+ }
149
+
150
  if ( get_option( 'users_can_register' ) ) {
151
  if ( is_multisite() ) {
152
  $this->do_redirect_with_token( 'register', 'wp-signup.php' );
252
  list( $clean_path ) = explode( '?', $path );
253
 
254
  if ( 'wp-login.php' === $clean_path && 'wp-login.php' !== $this->settings['slug'] ) {
255
+
256
+ $request_path = ITSEC_Lib::get_request_path();
257
+
258
  if ( false !== strpos( $path, 'action=postpass' ) ) {
259
  // No special handling is needed for a password-protected post.
260
  return $url;
261
  } else if ( false !== strpos( $path, 'action=register' ) ) {
262
  $url = $this->add_token_to_url( $url, 'register' );
263
+ } elseif ( 'wp-login.php' !== $request_path || empty( $_GET['action'] ) || 'register' !== $_GET['action'] ) {
264
  $url = $this->add_token_to_url( $url, 'login' );
265
  }
266
  } else if ( 'wp-signup.php' === $clean_path && 'wp-signup.php' !== $this->settings['register'] ) {
270
  return $url;
271
  }
272
 
273
+ /**
274
+ * Filter the admin URL to include hide backend tokens when necessary.
275
+ *
276
+ * @param string $url Complete admin URL.
277
+ * @param string $path Path passed to the admin_url function.
278
+ *
279
+ * @return string
280
+ */
281
+ public function filter_admin_url( $url, $path ) {
282
+
283
+ if ( 0 === strpos( $path, 'profile.php?newuseremail=' ) ) {
284
+ $url = $this->add_token_to_url( $url, 'login' );
285
+ }
286
+
287
+ return $url;
288
+ }
289
+
290
  /**
291
  * Filter redirection URLs to login and signup pages to include the access token query arg.
292
  *
344
  }
345
  }
346
 
347
+ /**
348
+ * Hide the navigation links on the registration page.
349
+ *
350
+ * These links have their security tokens removed in PHP. We only hide them for UX purposes as they would
351
+ * lead to a 404 page.
352
+ */
353
+ public function login_enqueue() {
354
+ if ( ! empty( $_GET['action'] ) && 'register' === $_GET['action'] ) {
355
+ wp_enqueue_style( 'itsec-hide-backend-login-page', plugins_url( 'css/login-page.css', __FILE__ ) );
356
+ }
357
+ }
358
+
359
  /**
360
  * Register the New Login URL notification.
361
  *
445
 
446
  return $this->settings['slug'];
447
  }
448
+
449
+ private function allow_access_to_wp_signup() {
450
+
451
+ if ( is_multisite() ) {
452
+ // Multisite will show its own error message and without links if signups are disabled.
453
+ return true;
454
+ }
455
+
456
+ if ( get_option( 'users_can_register' ) ) {
457
+ return true;
458
+ }
459
+
460
+ return false;
461
+ }
462
  }
core/modules/hide-backend/css/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden.
core/modules/hide-backend/css/login-page.css ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ #nav {
2
+ display: none;
3
+ }
core/modules/hide-backend/settings.php CHANGED
@@ -18,20 +18,23 @@ final class ITSEC_Hide_Backend_Settings extends ITSEC_Settings {
18
 
19
  protected function handle_settings_changes( $old_settings ) {
20
 
21
- if ( $this->settings['enabled'] && $this->settings['slug'] !== $old_settings['slug'] ) {
22
- $url = get_site_url() . '/' . $this->settings['slug'];
23
- } elseif ( $this->settings['enabled'] && ! $old_settings['enabled'] ) {
24
- $url = get_site_url() . '/' . $this->settings['slug'];
25
  } elseif ( ! $this->settings['enabled'] && $old_settings['enabled'] ) {
26
- $url = get_site_url() . '/wp-login.php';
 
 
 
 
27
  } else {
28
  return;
29
  }
30
 
31
- $this->send_new_login_url( $url );
32
  }
33
 
34
- private function send_new_login_url( $url ) {
35
  if ( ITSEC_Core::doing_data_upgrade() ) {
36
  // Do not send emails when upgrading data. This prevents spamming users with notifications just because the
37
  // data was ported from an old version to a new version.
@@ -39,7 +42,11 @@ final class ITSEC_Hide_Backend_Settings extends ITSEC_Settings {
39
  }
40
 
41
  $nc = ITSEC_Core::get_notification_center();
42
- $nc->clear_notifications_cache();
 
 
 
 
43
 
44
  $mail = $nc->mail();
45
 
18
 
19
  protected function handle_settings_changes( $old_settings ) {
20
 
21
+ if ( $this->settings['enabled'] && ! $old_settings['enabled'] ) {
22
+ $url = get_site_url() . '/' . $this->settings['slug'];
23
+ $enabling = true;
 
24
  } elseif ( ! $this->settings['enabled'] && $old_settings['enabled'] ) {
25
+ $url = get_site_url() . '/wp-login.php';
26
+ $enabling = false;
27
+ } elseif ( $this->settings['enabled'] && $this->settings['slug'] !== $old_settings['slug'] ) {
28
+ $url = get_site_url() . '/' . $this->settings['slug'];
29
+ $enabling = false;
30
  } else {
31
  return;
32
  }
33
 
34
+ $this->send_new_login_url( $url, $enabling );
35
  }
36
 
37
+ private function send_new_login_url( $url, $enabling ) {
38
  if ( ITSEC_Core::doing_data_upgrade() ) {
39
  // Do not send emails when upgrading data. This prevents spamming users with notifications just because the
40
  // data was ported from an old version to a new version.
42
  }
43
 
44
  $nc = ITSEC_Core::get_notification_center();
45
+
46
+ if ( $enabling ) {
47
+ $nc->clear_notifications_cache();
48
+ ITSEC_Modules::get_settings_obj( 'notification-center' )->load();
49
+ }
50
 
51
  $mail = $nc->mail();
52
 
core/modules/malware/sync-verbs/itsec-get-malware-scan-log.php CHANGED
@@ -19,7 +19,7 @@ class Ithemes_Sync_Verb_ITSEC_Get_Malware_Scan_Log extends Ithemes_Sync_Verb {
19
  foreach ( $items as $item ) {
20
  $item['log_data'] = maybe_unserialize( $item['log_data'] );
21
 
22
- if ( ! isset( $item['log_data']['SCAN']['SITE'] ) ) {
23
  // Don't return old scan data.
24
  continue;
25
  }
19
  foreach ( $items as $item ) {
20
  $item['log_data'] = maybe_unserialize( $item['log_data'] );
21
 
22
+ if ( ! is_array( $item['log_data'] ) || ! isset( $item['log_data']['SCAN']['SITE'] ) ) {
23
  // Don't return old scan data.
24
  continue;
25
  }
core/modules/wordpress-tweaks/class-itsec-wordpress-tweaks.php CHANGED
@@ -185,7 +185,7 @@ final class ITSEC_WordPress_Tweaks {
185
  return $result;
186
  }
187
 
188
- $route = $request->get_route();
189
  $route_parts = explode( '/', trim( $route, '/' ) );
190
 
191
  if ( 'wp' !== $route_parts[0] ) {
185
  return $result;
186
  }
187
 
188
+ $route = strtolower( $request->get_route() );
189
  $route_parts = explode( '/', trim( $route, '/' ) );
190
 
191
  if ( 'wp' !== $route_parts[0] ) {
core/sidebar-widget-active-lockouts.php CHANGED
@@ -15,6 +15,7 @@ class ITSEC_Settings_Page_Sidebar_Widget_Active_Lockouts extends ITSEC_Settings_
15
  global $itsec_lockout;
16
 
17
  $lockouts = $itsec_lockout->get_lockouts();
 
18
  $users = array();
19
  $hosts = array();
20
 
@@ -31,26 +32,36 @@ class ITSEC_Settings_Page_Sidebar_Widget_Active_Lockouts extends ITSEC_Settings_
31
 
32
  $data = array( $lockout['lockout_id'], $expiration );
33
 
34
- if ( ! empty( $lockout['lockout_username'] ) ) {
35
- $users[$lockout['lockout_username']] = $data;
36
- } else if ( ! empty( $lockout['lockout_host'] ) ) {
37
- $hosts[$lockout['lockout_host']] = $data;
 
 
38
  }
39
  }
40
 
41
 
42
- if ( empty( $users ) && empty( $hosts ) ) {
43
  echo '<p>' . __( 'There are no active lockouts at this time.', 'better-wp-security' ) . "</p>\n";
44
  return;
45
  }
46
 
47
  if ( ! empty( $users ) ) {
48
- //echo '<p>' . _n( 'The following user is currently locked out from logging in:', 'The following users are currently locked out from logging in:', count( $users ), 'better-wp-security' ) . "</p>\n";
49
- echo '<p><strong>' . _n( 'User', 'Users', count( $users ), 'better-wp-security' ) . "</strong></p>\n";
50
  echo "<ul>\n";
51
 
52
- foreach ( $users as $user => $data ) {
53
- $label = sprintf( _x( '%1$s - Expires in %2$s', 'USER - Expires in TIME', 'better-wp-security' ), '<strong>' . esc_html( $user ) . '</strong>', '<em>' . human_time_diff( $data[1] ) . '</em>' );
 
 
 
 
 
 
 
 
 
54
  echo '<li><label>';
55
  $form->add_multi_checkbox( 'users', $data[0] );
56
  echo " $label</label></li>\n";
@@ -59,13 +70,28 @@ class ITSEC_Settings_Page_Sidebar_Widget_Active_Lockouts extends ITSEC_Settings_
59
  echo "</ul>\n";
60
  }
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  if ( ! empty( $hosts ) ) {
63
- //echo '<p>' . _n( 'The following host is currently locked out from accessing the site:', 'The following hosts are currently locked out from accessing the site:', count( $hosts ), 'better-wp-security' ) . "</p>\n";
64
- echo '<p><strong>' . _n( 'Host', 'Hosts', count( $hosts ), 'better-wp-security' ) . "</strong></p>\n";
65
  echo "<ul>\n";
66
 
67
  foreach ( $hosts as $host => $data ) {
68
- $label = sprintf( _x( '%1$s - Expires in %2$s', 'HOST - Expires in TIME', 'better-wp-security' ), '<strong>' . esc_html( strtoupper( $host ) ) . '</strong>', '<em>' . human_time_diff( $data[1] ) . '</em>' );
 
69
  echo '<li><label>';
70
  $form->add_multi_checkbox( 'hosts', $data[0] );
71
  echo " $label</label></li>\n";
@@ -92,7 +118,18 @@ class ITSEC_Settings_Page_Sidebar_Widget_Active_Lockouts extends ITSEC_Settings_
92
  $count++;
93
 
94
  if ( ! $result ) {
95
- $this->errors[] = sprintf( __( 'An unknown error prevented releasing the lockout the user with a lockout ID of %d', 'better-wp-security' ), $id );
 
 
 
 
 
 
 
 
 
 
 
96
  }
97
  }
98
  }
@@ -103,14 +140,14 @@ class ITSEC_Settings_Page_Sidebar_Widget_Active_Lockouts extends ITSEC_Settings_
103
  $count++;
104
 
105
  if ( ! $result ) {
106
- $this->errors[] = sprintf( __( 'An unknown error prevented releasing the lockout the host with a lockout ID of %d', 'better-wp-security' ), $id );
107
  }
108
  }
109
  }
110
 
111
  if ( empty( $this->errors ) ) {
112
  if ( $count > 0 ) {
113
- $this->messages[] = _n( 'Successfully removed the selected lockout.', 'Sucessfully remove the selected lockouts.', $count, 'better-wp-security' );
114
  } else {
115
  $this->errors[] = __( 'No lockouts were selected for removal.', 'better-wp-security' );
116
  }
15
  global $itsec_lockout;
16
 
17
  $lockouts = $itsec_lockout->get_lockouts();
18
+ $usernames = array();
19
  $users = array();
20
  $hosts = array();
21
 
32
 
33
  $data = array( $lockout['lockout_id'], $expiration );
34
 
35
+ if ( ! empty( $lockout['lockout_user'] ) ) {
36
+ $users[ $lockout['lockout_user'] ] = $data;
37
+ } elseif ( ! empty( $lockout['lockout_username'] ) ) {
38
+ $usernames[ $lockout['lockout_username'] ] = $data;
39
+ } elseif ( ! empty( $lockout['lockout_host'] ) ) {
40
+ $hosts[ $lockout['lockout_host'] ] = $data;
41
  }
42
  }
43
 
44
 
45
+ if ( ! $users && ! $usernames && ! $hosts ) {
46
  echo '<p>' . __( 'There are no active lockouts at this time.', 'better-wp-security' ) . "</p>\n";
47
  return;
48
  }
49
 
50
  if ( ! empty( $users ) ) {
51
+ echo '<p><strong>' . __( 'Users', 'better-wp-security' ) . "</strong></p>\n";
 
52
  echo "<ul>\n";
53
 
54
+ foreach ( $users as $user_id => $data ) {
55
+ $user = get_userdata( $user_id );
56
+
57
+ if ( $user ) {
58
+ $label = $user->user_login;
59
+ } else {
60
+ $label = sprintf( __( 'Deleted #%d', 'better-wp-security' ), $user_id );
61
+ }
62
+
63
+ /* translators: 1. Username 2. Expiration as human time diff */
64
+ $label = sprintf( _x( '%1$s - Expires in %2$s', 'User lockout', 'better-wp-security' ), "<strong>{$label}</strong>", '<em>' . human_time_diff( $data[1] ) . '</em>' );
65
  echo '<li><label>';
66
  $form->add_multi_checkbox( 'users', $data[0] );
67
  echo " $label</label></li>\n";
70
  echo "</ul>\n";
71
  }
72
 
73
+ if ( ! empty( $usernames ) ) {
74
+ echo '<p><strong>' . __( 'Usernames', 'better-wp-security' ) . "</strong></p>\n";
75
+ echo "<ul>\n";
76
+
77
+ foreach ( $usernames as $username => $data ) {
78
+ /* translators: 1. Username 2. Expiration as human time diff */
79
+ $label = sprintf( _x( '%1$s - Expires in %2$s', 'Username lockout', 'better-wp-security' ), '<strong>' . esc_html( $username ) . '</strong>', '<em>' . human_time_diff( $data[1] ) . '</em>' );
80
+ echo '<li><label>';
81
+ $form->add_multi_checkbox( 'usernames', $data[0] );
82
+ echo " $label</label></li>\n";
83
+ }
84
+
85
+ echo "</ul>\n";
86
+ }
87
+
88
  if ( ! empty( $hosts ) ) {
89
+ echo '<p><strong>' . __( 'Hosts', 'better-wp-security' ) . "</strong></p>\n";
 
90
  echo "<ul>\n";
91
 
92
  foreach ( $hosts as $host => $data ) {
93
+ /* translators: 1. IP Address 2. Expiration as human time diff */
94
+ $label = sprintf( _x( '%1$s - Expires in %2$s', 'Host lockout', 'better-wp-security' ), '<strong>' . esc_html( strtoupper( $host ) ) . '</strong>', '<em>' . human_time_diff( $data[1] ) . '</em>' );
95
  echo '<li><label>';
96
  $form->add_multi_checkbox( 'hosts', $data[0] );
97
  echo " $label</label></li>\n";
118
  $count++;
119
 
120
  if ( ! $result ) {
121
+ $this->errors[] = sprintf( __( 'An unknown error prevented releasing the user lockout with a lockout ID of %d', 'better-wp-security' ), $id );
122
+ }
123
+ }
124
+ }
125
+
126
+ if ( ! empty( $data['usernames'] ) && is_array( $data['usernames'] ) ) {
127
+ foreach ( $data['usernames'] as $id ) {
128
+ $result = $itsec_lockout->release_lockout( $id );
129
+ $count++;
130
+
131
+ if ( ! $result ) {
132
+ $this->errors[] = sprintf( __( 'An unknown error prevented releasing the username lockout with a lockout ID of %d', 'better-wp-security' ), $id );
133
  }
134
  }
135
  }
140
  $count++;
141
 
142
  if ( ! $result ) {
143
+ $this->errors[] = sprintf( __( 'An unknown error prevented releasing the host lockout with a lockout ID of %d', 'better-wp-security' ), $id );
144
  }
145
  }
146
  }
147
 
148
  if ( empty( $this->errors ) ) {
149
  if ( $count > 0 ) {
150
+ $this->messages[] = _n( 'Successfully removed the selected lockout.', 'Successfully remove the selected lockouts.', $count, 'better-wp-security' );
151
  } else {
152
  $this->errors[] = __( 'No lockouts were selected for removal.', 'better-wp-security' );
153
  }
history.txt CHANGED
@@ -709,3 +709,11 @@
709
  Bug Fix: Fixed issue where scheduled events could repeat on sites that do not properly support WordPress's cron system.
710
  Bug Fix: Reactivating Away Mode now replaces the active file if you had previously removed it.
711
  Bug Fix: Ensure lockouts take effect immediately, even on systems where changes to server configuration files do not take effect immediately.
 
 
 
 
 
 
 
 
709
  Bug Fix: Fixed issue where scheduled events could repeat on sites that do not properly support WordPress's cron system.
710
  Bug Fix: Reactivating Away Mode now replaces the active file if you had previously removed it.
711
  Bug Fix: Ensure lockouts take effect immediately, even on systems where changes to server configuration files do not take effect immediately.
712
+ 6.8.1 - 2017-01-29 - Chris Jean & Timothy Jacobs
713
+ Enhancement: Display user lockouts in Lockout Sidebar.
714
+ Bug Fix: Load translations on the plugins_loaded hook.
715
+ Bug Fix: Fixed method that could be used to discover hidden login slug on some sites.
716
+ Bug Fix: Fixed issue that could prevent Sync from loading Malware Scan results if a scan previously failed.
717
+ Bug Fix: Update to the REST API "Restricted Access" feature to protect against methods to work around the restricted access.
718
+ Bug Fix: Prevent login page being hidden when following the "Confirm Email Address" notification URL.
719
+ Bug Fix: Hide Backend notifications not being properly sent when first enabled.
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: ithemes, chrisjean, gerroald, mattdanner, timothyblynjacobs
3
  Tags: security, security plugin, malware, hack, secure, block, SSL, admin, htaccess, lockdown, login, protect, protection, anti virus, attack, injection, login security, maintenance, permissions, prevention, authentication, administration, password, brute force, ban, permissions, bots, user agents, xml rpc, security log
4
  Requires at least: 4.7
5
- Tested up to: 4.9.1
6
- Stable tag: 6.8.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -188,6 +188,15 @@ Free support may be available with the help of the community in the <a href="htt
188
 
189
  == Changelog ==
190
 
 
 
 
 
 
 
 
 
 
191
  = 6.8.0 =
192
  * New Feature: Introduces a scheduling framework for handling events. Cron is now used by default, and will switch to using an alternate scheduling system if it detects an error. To disable this detection set ITSEC_DISABLE_CRON_TEST in your wp-config.php file.
193
  * Important: The ITSEC_FILE_CHECK_CRON and ITSEC_BACKUP_CRON constants have been deprecated. Use ITSEC_USE_CRON instead.
@@ -391,5 +400,5 @@ Free support may be available with the help of the community in the <a href="htt
391
 
392
  == Upgrade Notice ==
393
 
394
- = 6.8.0 =
395
- Version 6.8.0 contains important bug fixes and improvements. It is recommended for all users.
2
  Contributors: ithemes, chrisjean, gerroald, mattdanner, timothyblynjacobs
3
  Tags: security, security plugin, malware, hack, secure, block, SSL, admin, htaccess, lockdown, login, protect, protection, anti virus, attack, injection, login security, maintenance, permissions, prevention, authentication, administration, password, brute force, ban, permissions, bots, user agents, xml rpc, security log
4
  Requires at least: 4.7
5
+ Tested up to: 4.9.2
6
+ Stable tag: 6.8.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
188
 
189
  == Changelog ==
190
 
191
+ = 6.8.1 =
192
+ * Enhancement: Display user lockouts in Lockout Sidebar.
193
+ * Bug Fix: Load translations on the plugins_loaded hook.
194
+ * Bug Fix: Fixed method that could be used to discover hidden login slug on some sites.
195
+ * Bug Fix: Fixed issue that could prevent Sync from loading Malware Scan results if a scan previously failed.
196
+ * Bug Fix: Update to the REST API "Restricted Access" feature to protect against methods to work around the restricted access.
197
+ * Bug Fix: Prevent login page being hidden when following the "Confirm Email Address" notification URL.
198
+ * Bug Fix: Hide Backend notifications not being properly sent when first enabled.
199
+
200
  = 6.8.0 =
201
  * New Feature: Introduces a scheduling framework for handling events. Cron is now used by default, and will switch to using an alternate scheduling system if it detects an error. To disable this detection set ITSEC_DISABLE_CRON_TEST in your wp-config.php file.
202
  * Important: The ITSEC_FILE_CHECK_CRON and ITSEC_BACKUP_CRON constants have been deprecated. Use ITSEC_USE_CRON instead.
400
 
401
  == Upgrade Notice ==
402
 
403
+ = 6.8.1 =
404
+ Version 6.8.1 contains important bug fixes and improvements. It is recommended for all users.