WP Security Audit Log - Version 4.1.0

Version Description

(2020-05-26) =

Release notes: New session policies per user roles & other improvements

  • New Features

    • New WordPress users sessions management module with configurable policies per user role.
    • Setting to configure the log files location (request log file, 6007 and 6023 events).
  • Plugin Improvements

    • Activity log reports now support user roles which have the space character in the name.
    • Removed more legacy code from the plugin (the check for encryption method).
    • Removed old update scripts (for when updating from versions prior to 3.5.2).
    • Moved 10 more plugin settings from the custom table to the wp_options table (performance improvement).
    • Standardized the format of all placeholders in the UI (now they are all using default WordPress format).
    • Removed premium only code from free edition.
  • Bug fixes

    • Scheduled daily reports included data of the last 24 hours instead of the previous day.
    • Resaving the activity logs archiving settings generated errors (didn't check if connection was already setup).
    • Issue with the plugin when installed on MainWP child sites (support ticket).
    • Plugin adding Menu entry with no title (used by the wizard).

Refer to the complete plugin changelog for more detailed information about what was new, improved and fixed in previous versions of the WP Activity Log plugin.

Download this release

Release Info

Developer WPWhiteSecurity
Plugin Icon 128x128 WP Security Audit Log
Version 4.1.0
Comparing to
See all releases

Code changes from version 4.0.4 to 4.1.0

classes/Adapters/MySQL/MetaAdapter.php CHANGED
@@ -147,6 +147,14 @@ class WSAL_Adapters_MySQL_Meta extends WSAL_Adapters_MySQL_ActiveRecord implemen
147
  */
148
  public function create_indexes() {
149
  $db_connection = $this->get_connection();
150
- $db_connection->query( 'CREATE INDEX name_value ON ' . $this->GetTable() . ' (name, value(64))' );
 
 
 
 
 
 
 
 
151
  }
152
  }
147
  */
148
  public function create_indexes() {
149
  $db_connection = $this->get_connection();
150
+ // check if an index exists.
151
+ if ( $db_connection->query( 'SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() AND table_name="' . $this->GetTable() . '" AND index_name="name_value"' ) ) {
152
+ // query succeeded, does index exist?
153
+ $index_exists = ( isset( $db_connection->last_result[0]->IndexIsThere ) ) ? $db_connection->last_result[0]->IndexIsThere : false;
154
+ }
155
+ // if no index exists then make one.
156
+ if ( ! $index_exists ) {
157
+ $db_connection->query( 'CREATE INDEX name_value ON ' . $this->GetTable() . ' (name, value(64))' );
158
+ }
159
  }
160
  }
classes/Adapters/MySQL/OccurrenceAdapter.php CHANGED
@@ -318,6 +318,14 @@ class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord im
318
  */
319
  public function create_indexes() {
320
  $db_connection = $this->get_connection();
321
- $db_connection->query( 'CREATE INDEX created_on ON ' . $this->GetTable() . ' (created_on)' );
 
 
 
 
 
 
 
 
322
  }
323
  }
318
  */
319
  public function create_indexes() {
320
  $db_connection = $this->get_connection();
321
+ // check if an index exists.
322
+ if ( $db_connection->query( 'SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() AND table_name="' . $this->GetTable() . '" AND index_name="created_on"' ) ) {
323
+ // query succeeded, does index exist?
324
+ $index_exists = ( isset( $db_connection->last_result[0]->IndexIsThere ) ) ? $db_connection->last_result[0]->IndexIsThere : false;
325
+ }
326
+ // if no index exists then make one.
327
+ if ( ! $index_exists ) {
328
+ $db_connection->query( 'CREATE INDEX created_on ON ' . $this->GetTable() . ' (created_on)' );
329
+ }
330
  }
331
  }
classes/Adapters/MySQL/OptionAdapter.php CHANGED
@@ -172,6 +172,14 @@ class WSAL_Adapters_MySQL_Option extends WSAL_Adapters_MySQL_ActiveRecord {
172
  */
173
  public function create_indexes() {
174
  $db_connection = $this->get_connection();
175
- $db_connection->query( 'CREATE INDEX option_name ON ' . $this->GetTable() . ' (option_name)' );
 
 
 
 
 
 
 
 
176
  }
177
  }
172
  */
173
  public function create_indexes() {
174
  $db_connection = $this->get_connection();
175
+ // check if an index exists.
176
+ if ( $db_connection->query( 'SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() AND table_name="' . $this->GetTable() . '" AND index_name="option_name"' ) ) {
177
+ // query succeeded, does index exist?
178
+ $index_exists = ( isset( $db_connection->last_result[0]->IndexIsThere ) ) ? $db_connection->last_result[0]->IndexIsThere : false;
179
+ }
180
+ // if no index exists then make one.
181
+ if ( ! $index_exists ) {
182
+ $db_connection->query( 'CREATE INDEX option_name ON ' . $this->GetTable() . ' (option_name)' );
183
+ }
184
  }
185
  }
classes/AlertManager.php CHANGED
@@ -576,14 +576,14 @@ final class WSAL_AlertManager {
576
  $event_data['CurrentUserRoles'] = $current_user_roles;
577
  }
578
  }
579
- // Check if the user management plugin is loaded and adds the SessionID.
580
- if ( class_exists( 'WSAL_User_Management_Plugin' ) ) {
581
- if ( function_exists( 'get_current_user_id' ) ) {
582
- $session_tokens = get_user_meta( get_current_user_id(), 'session_tokens', true );
583
- if ( ! empty( $session_tokens ) ) {
584
- end( $session_tokens );
585
- $event_data['SessionID'] = key( $session_tokens );
586
- }
587
  }
588
  }
589
 
576
  $event_data['CurrentUserRoles'] = $current_user_roles;
577
  }
578
  }
579
+
580
+ // If the user sessions plugin is loaded try attach the SessionID.
581
+ if ( ! isset( $event_data['SessionID'] ) && class_exists( 'WSAL_UserSessions_Helpers' ) ) {
582
+ // try get the session id generated from logged in cookie.
583
+ $session_id = WSAL_UserSessions_Helpers::get_session_id_from_logged_in_user_cookie();
584
+ // if we have a SessionID then add it to event_data.
585
+ if ( ! empty( $session_id ) ) {
586
+ $event_data['SessionID'] = $session_id;
587
  }
588
  }
589
 
classes/Connector/AbstractConnector.php CHANGED
@@ -64,6 +64,7 @@ abstract class WSAL_Connector_AbstractConnector {
64
  require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'OccurrenceAdapter.php' );
65
  require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'QueryAdapter.php' );
66
  require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'TmpUserAdapter.php' );
 
67
  }
68
  }
69
 
64
  require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'OccurrenceAdapter.php' );
65
  require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'QueryAdapter.php' );
66
  require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'TmpUserAdapter.php' );
67
+ do_action( 'wsal_require_additional_adapters' );
68
  }
69
  }
70
 
classes/Connector/MySQLDB.php CHANGED
@@ -175,13 +175,17 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
175
  */
176
  public function installAll( $exclude_options = false ) {
177
  $plugin = WpSecurityAuditLog::GetInstance();
178
-
179
- foreach ( glob( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php' ) as $file ) {
 
180
  $file_path = explode( DIRECTORY_SEPARATOR, $file );
181
  $file_name = $file_path[ count( $file_path ) - 1 ];
182
  $class_name = $this->getAdapterClassName( str_replace( 'Adapter.php', '', $file_name ) );
183
 
184
- $class = new $class_name( $this->getConnection() );
 
 
 
185
  if ( $exclude_options && $class instanceof WSAL_Adapters_MySQL_Option ) {
186
  continue;
187
  }
@@ -418,9 +422,6 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
418
  * @since 2.6.3
419
  */
420
  public function encryptString( $plaintext ) {
421
- // Check for previous version.
422
- $plugin = WpSecurityAuditLog::GetInstance();
423
- $version = $plugin->options_helper->get_option_value( 'version', '0.0.0' );
424
 
425
  $ciphertext = false;
426
  $encrypt_method = 'AES-256-CBC';
@@ -459,9 +460,6 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
459
  * @since 2.6.3
460
  */
461
  public function decryptString( $ciphertext_base64 ) {
462
- // Check for previous version.
463
- $plugin = WpSecurityAuditLog::GetInstance();
464
- $version = $plugin->options_helper->get_option_value( 'version', '0.0.0' );
465
 
466
  $plaintext = false;
467
  $encrypt_method = 'AES-256-CBC';
175
  */
176
  public function installAll( $exclude_options = false ) {
177
  $plugin = WpSecurityAuditLog::GetInstance();
178
+ $adapter_list = glob( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php' );
179
+ $adapter_list = apply_filters( 'wsal_install_apapters_list', $adapter_list );
180
+ foreach ( $adapter_list as $file ) {
181
  $file_path = explode( DIRECTORY_SEPARATOR, $file );
182
  $file_name = $file_path[ count( $file_path ) - 1 ];
183
  $class_name = $this->getAdapterClassName( str_replace( 'Adapter.php', '', $file_name ) );
184
 
185
+ if ( class_exists( $class_name ) ) {
186
+ $class = new $class_name( $this->getConnection() );
187
+ }
188
+
189
  if ( $exclude_options && $class instanceof WSAL_Adapters_MySQL_Option ) {
190
  continue;
191
  }
422
  * @since 2.6.3
423
  */
424
  public function encryptString( $plaintext ) {
 
 
 
425
 
426
  $ciphertext = false;
427
  $encrypt_method = 'AES-256-CBC';
460
  * @since 2.6.3
461
  */
462
  public function decryptString( $ciphertext_base64 ) {
 
 
 
463
 
464
  $plaintext = false;
465
  $encrypt_method = 'AES-256-CBC';
classes/Connector/wp-db-custom.php CHANGED
@@ -45,7 +45,6 @@ class wpdbCustom extends wpdb {
45
  * @param bool $test_connection - Set to true if testing connection.
46
  */
47
  public function __construct( $dbuser, $dbpassword, $dbname, $dbhost, $is_ssl, $is_cc, $ssl_ca, $ssl_cert, $ssl_key, $test_connection = false ) {
48
- register_shutdown_function( array( $this, '__destruct' ) );
49
 
50
  if ( WP_DEBUG && WP_DEBUG_DISPLAY ) {
51
  $this->show_errors();
@@ -319,4 +318,5 @@ class wpdbCustom extends wpdb {
319
  }
320
  }
321
  }
 
322
  }
45
  * @param bool $test_connection - Set to true if testing connection.
46
  */
47
  public function __construct( $dbuser, $dbpassword, $dbname, $dbhost, $is_ssl, $is_cc, $ssl_ca, $ssl_cert, $ssl_key, $test_connection = false ) {
 
48
 
49
  if ( WP_DEBUG && WP_DEBUG_DISPLAY ) {
50
  $this->show_errors();
318
  }
319
  }
320
  }
321
+
322
  }
classes/Helpers/Options.php CHANGED
@@ -103,7 +103,8 @@ class Options {
103
  /**
104
  * Deletes an option from the WP options table.
105
  *
106
- * NOTE: This is just a strait wrapper around the core function.
 
107
  *
108
  * @method delete_option
109
  * @since 4.0.2
@@ -114,4 +115,44 @@ class Options {
114
  return \delete_option( $option_name );
115
  }
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  }
103
  /**
104
  * Deletes an option from the WP options table.
105
  *
106
+ * NOTE: This is just a strait wrapper around the core function - if the
107
+ * item is prefixed then pass the prefix in the option name.
108
  *
109
  * @method delete_option
110
  * @since 4.0.2
115
  return \delete_option( $option_name );
116
  }
117
 
118
+ /**
119
+ * Retrieves the logging directory from the settings. Returns a file path
120
+ * with a trailing slash.
121
+ *
122
+ * Uses as default:
123
+ * /wp-content/uploads/wp-security-audit-log/
124
+ *
125
+ * @method get_logging_path
126
+ * @since 4.1.0
127
+ * @return string
128
+ */
129
+ public function get_logging_path() {
130
+ if ( ! \function_exists( 'get_home_path' ) ) {
131
+ require_once ABSPATH . 'wp-admin/includes/file.php';
132
+ }
133
+ $relative_path = $this->get_option_value( 'custom-logging-dir', \WSAL_Settings::DEFAULT_LOGGING_DIR );
134
+ $absolute_path = trailingslashit( \get_home_path() ) . trailingslashit( ltrim( $relative_path, '/' ) );
135
+ return $absolute_path;
136
+ }
137
+
138
+ /**
139
+ * Retrieves the logging directory from the settings to generate a url.
140
+ * Returns a url with a trailing slash.
141
+ *
142
+ * Uses as default:
143
+ * /wp-content/uploads/wp-security-audit-log/
144
+ *
145
+ * @method get_logging_url
146
+ * @since 4.1.0
147
+ * @return string
148
+ */
149
+ public function get_logging_url() {
150
+ if ( ! \function_exists( 'get_home_url' ) ) {
151
+ require_once ABSPATH . 'wp-admin/includes/file.php';
152
+ }
153
+ $relative_url = $this->get_option_value( 'custom-logging-dir', \WSAL_Settings::DEFAULT_LOGGING_DIR );
154
+ $absolute_url = trailingslashit( \get_site_url() ) . trailingslashit( ltrim( $relative_url, '/' ) );
155
+ return $absolute_url;
156
+ }
157
+
158
  }
classes/Loggers/Database.php CHANGED
@@ -300,7 +300,7 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
300
  && ! class_exists( 'WSAL_Ext_Plugin' )
301
  && ! class_exists( 'WSAL_Rep_Plugin' )
302
  && ! class_exists( 'WSAL_SearchExtension' )
303
- && ! class_exists( 'WSAL_User_Management_Plugin' ) ) {
304
  return 150;
305
  }
306
  return null;
300
  && ! class_exists( 'WSAL_Ext_Plugin' )
301
  && ! class_exists( 'WSAL_Rep_Plugin' )
302
  && ! class_exists( 'WSAL_SearchExtension' )
303
+ && ! class_exists( 'WSAL_UserSessions_Plugin' ) ) {
304
  return 150;
305
  }
306
  return null;
classes/SensorManager.php CHANGED
@@ -61,7 +61,7 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
61
  * Passed through a filter so other plugins or code can add own custom
62
  * sensor class files by adding the containing directory to this array.
63
  *
64
- * @since 3.5.2 - Added the `wsal_custom_sensors_classes_dirs` filter.
65
  */
66
  $paths = apply_filters( 'wsal_custom_sensors_classes_dirs', array( $uploads_dir_path ) );
67
  foreach ( $paths as $inc_path ) {
@@ -79,8 +79,8 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
79
  }
80
 
81
  /*
82
- * @since 3.5.2 Allow loading classes where names match the
83
- * filename 1:1. Prior to version 3.5.2 sensors were always
84
  * asummed to be defined WITH `WSAL_Sensors_` prefis in the
85
  * class name but WITHOUT it in the filename. This behavor
86
  * is retained for back-compat.
61
  * Passed through a filter so other plugins or code can add own custom
62
  * sensor class files by adding the containing directory to this array.
63
  *
64
+ * @since 3.5.1 - Added the `wsal_custom_sensors_classes_dirs` filter.
65
  */
66
  $paths = apply_filters( 'wsal_custom_sensors_classes_dirs', array( $uploads_dir_path ) );
67
  foreach ( $paths as $inc_path ) {
79
  }
80
 
81
  /*
82
+ * @since 3.5.1 Allow loading classes where names match the
83
+ * filename 1:1. Prior to version 3.5.1 sensors were always
84
  * asummed to be defined WITH `WSAL_Sensors_` prefis in the
85
  * class name but WITHOUT it in the filename. This behavor
86
  * is retained for back-compat.
classes/Sensors/FrontendLogin.php CHANGED
@@ -18,33 +18,58 @@ class WSAL_Sensors_FrontendLogin extends WSAL_AbstractSensor {
18
  * Listening to events using WP hooks.
19
  */
20
  public function HookEvents() {
21
- add_action( 'wp_login', array( $this, 'event_login' ), 10, 2 );
22
  }
23
 
24
  /**
25
  * Event Login.
26
  *
27
- * @param string $user_login - Username.
28
- * @param object $user - WP_User object.
29
  */
30
- public function event_login( $user_login, $user ) {
31
- if ( empty( $user ) ) {
32
- $user = get_user_by( 'login', $user_login );
 
 
 
33
  }
34
 
 
35
  $user_roles = $this->plugin->settings->GetCurrentUserRoles( $user->roles );
36
 
37
  if ( $this->plugin->settings->IsLoginSuperAdmin( $user_login ) ) {
38
  $user_roles[] = 'superadmin';
39
  }
40
 
 
 
 
 
 
 
 
 
41
  $this->plugin->alerts->Trigger(
42
  1000,
43
- array(
44
- 'Username' => $user_login,
45
- 'CurrentUserRoles' => $user_roles,
46
- ),
47
  true
48
  );
49
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  }
18
  * Listening to events using WP hooks.
19
  */
20
  public function HookEvents() {
21
+ add_action( 'set_auth_cookie', array( $this, 'event_login' ), 10, 6 );
22
  }
23
 
24
  /**
25
  * Event Login.
26
  *
27
+ * TODO: update params doc block to match the new hook it's attached to.
 
28
  */
29
+ public function event_login( $auth_cookie, $expire, $expiration, $user_id, $scheme, $token ) {
30
+
31
+ $user = get_user_by( 'id', $user_id );
32
+ if ( ! is_a( $user, '\WP_User' ) ) {
33
+ // not a user logging in, return early.
34
+ return;
35
  }
36
 
37
+ $user_login = $user->data->user_login;
38
  $user_roles = $this->plugin->settings->GetCurrentUserRoles( $user->roles );
39
 
40
  if ( $this->plugin->settings->IsLoginSuperAdmin( $user_login ) ) {
41
  $user_roles[] = 'superadmin';
42
  }
43
 
44
+ $alert_data = array(
45
+ 'Username' => $user_login,
46
+ 'CurrentUserRoles' => $user_roles,
47
+ );
48
+ if ( class_exists( 'WSAL_UserSessions_Helpers' ) ) {
49
+ $alert_data['SessionID'] = $this->hash_token( $token );
50
+ }
51
+
52
  $this->plugin->alerts->Trigger(
53
  1000,
54
+ $alert_data,
 
 
 
55
  true
56
  );
57
  }
58
+
59
+ /**
60
+ * Hashes the given session token.
61
+ *
62
+ * NOTE: This is how core session manager does it.
63
+ *
64
+ * @param string $token Session token to hash.
65
+ * @return string A hash of the session token (a verifier).
66
+ */
67
+ public static function hash_token( $token ) {
68
+ // If ext/hash is not present, use sha1() instead.
69
+ if ( function_exists( 'hash' ) ) {
70
+ return hash( 'sha256', $token );
71
+ } else {
72
+ return sha1( $token );
73
+ }
74
+ }
75
  }
classes/Sensors/FrontendSystem.php CHANGED
@@ -204,9 +204,9 @@ class WSAL_Sensors_FrontendSystem extends WSAL_AbstractSensor {
204
  private function write_log( $attempts, $ip, $username = '', $url = null ) {
205
  $name_file = null;
206
 
207
- if ( 'on' === $this->plugin->GetGlobalOption( 'log-visitor-404', 'off' ) ) {
208
  // Get option to log referrer.
209
- $log_referrer = $this->plugin->GetGlobalOption( 'log-visitor-404-referrer' );
210
 
211
  // Check localhost.
212
  if ( '127.0.0.1' == $ip || '::1' == $ip ) {
@@ -239,16 +239,26 @@ class WSAL_Sensors_FrontendSystem extends WSAL_AbstractSensor {
239
  $data = $data . 'Request URL ' . $url . ',';
240
  }
241
 
242
- $username = '';
243
- $upload_dir = wp_upload_dir();
244
- $uploads_url = trailingslashit( $upload_dir['baseurl'] ) . 'wp-security-audit-log/404s/';
245
- $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/404s/';
 
 
 
 
 
 
 
 
 
 
246
 
247
  // Check directory.
248
- if ( $this->CheckDirectory( $uploads_dir_path ) ) {
249
  $filename = '6023_' . date( 'Ymd' ) . '.log';
250
- $fp = $uploads_dir_path . $filename;
251
- $name_file = $uploads_url . $filename;
252
  if ( ! $file = fopen( $fp, 'a' ) ) {
253
  $i = 1;
254
  $file_opened = false;
@@ -257,14 +267,14 @@ class WSAL_Sensors_FrontendSystem extends WSAL_AbstractSensor {
257
  if ( ! file_exists( $fp2 ) ) {
258
  if ( $file = fopen( $fp2, 'a' ) ) {
259
  $file_opened = true;
260
- $name_file = $uploads_url . substr( $name_file, 0, -4 ) . '_' . $i . '.log';
261
  }
262
  } else {
263
- $latest_filename = $this->GetLastModified( $uploads_dir_path, $filename );
264
- $fp_last = $uploads_dir_path . $latest_filename;
265
  if ( $file = fopen( $fp_last, 'a' ) ) {
266
  $file_opened = true;
267
- $name_file = $uploads_url . $latest_filename;
268
  }
269
  }
270
  $i++;
204
  private function write_log( $attempts, $ip, $username = '', $url = null ) {
205
  $name_file = null;
206
 
207
+ if ( 'on' === $this->plugin->options_helper->get_option_value( 'log-visitor-404', 'off' ) ) {
208
  // Get option to log referrer.
209
+ $log_referrer = $this->plugin->options_helper->get_option_value( 'log-visitor-404-referrer' );
210
 
211
  // Check localhost.
212
  if ( '127.0.0.1' == $ip || '::1' == $ip ) {
239
  $data = $data . 'Request URL ' . $url . ',';
240
  }
241
 
242
+ // don't store username in a public viewable logfile.
243
+ $username = '';
244
+
245
+ // get the custom logging path from settings.
246
+ $custom_logging_path = $this->plugin->options_helper->get_logging_path() . '404s/';
247
+ $custom_logging_url = $this->plugin->options_helper->get_logging_url() . '404s/';
248
+
249
+ if ( ! $this->CheckDirectory( $custom_logging_path ) ) {
250
+ $dir_made = wp_mkdir_p( $custom_logging_path );
251
+ if ( $dir_made ) {
252
+ // make an empty index.php in the directory.
253
+ @file_put_contents( $custom_logging_path . 'index.php', '<?php // Silence is golden' );
254
+ }
255
+ }
256
 
257
  // Check directory.
258
+ if ( $this->CheckDirectory( $custom_logging_path ) ) {
259
  $filename = '6023_' . date( 'Ymd' ) . '.log';
260
+ $fp = $custom_logging_path . $filename;
261
+ $name_file = $custom_logging_url . $filename;
262
  if ( ! $file = fopen( $fp, 'a' ) ) {
263
  $i = 1;
264
  $file_opened = false;
267
  if ( ! file_exists( $fp2 ) ) {
268
  if ( $file = fopen( $fp2, 'a' ) ) {
269
  $file_opened = true;
270
+ $name_file = $custom_logging_url . substr( $name_file, 0, -4 ) . '_' . $i . '.log';
271
  }
272
  } else {
273
+ $latest_filename = $this->GetLastModified( $custom_logging_path, $filename );
274
+ $fp_last = $custom_logging_path . $latest_filename;
275
  if ( $file = fopen( $fp_last, 'a' ) ) {
276
  $file_opened = true;
277
+ $name_file = $custom_logging_url . $latest_filename;
278
  }
279
  }
280
  $i++;
classes/Sensors/LogInOut.php CHANGED
@@ -46,7 +46,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
46
  * Listening to events using WP hooks.
47
  */
48
  public function HookEvents() {
49
- add_action( 'wp_login', array( $this, 'EventLogin' ), 10, 2 );
50
  add_action( 'wp_logout', array( $this, 'EventLogout' ), 5 );
51
  add_action( 'password_reset', array( $this, 'EventPasswordReset' ), 10, 2 );
52
  add_action( 'wp_login_failed', array( $this, 'EventLoginFailure' ) );
@@ -146,10 +146,9 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
146
  /**
147
  * Event Login.
148
  *
149
- * @param string $user_login - Username.
150
- * @param object $user - WP_User object.
151
  */
152
- public function EventLogin( $user_login, $user ) {
153
  // Get global POST array.
154
  $post_array = filter_input_array( INPUT_POST );
155
 
@@ -175,9 +174,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
175
  && $post_array['current_user_password'] !== $post_array['user_password'] // If current & new password don't match.
176
  && $post_array['user_password'] === $post_array['confirm_user_password'] ) { // And new & confirm password are same then.
177
  // Get user.
178
- if ( empty( $user ) ) {
179
- $user = get_user_by( 'login', $user_login );
180
- }
181
 
182
  // Log user changed password alert.
183
  if ( ! empty( $user ) ) {
@@ -195,24 +192,32 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
195
  return; // Return.
196
  }
197
 
198
- if ( empty( $user ) ) {
199
- $user = get_user_by( 'login', $user_login );
 
 
200
  }
201
-
202
  $user_roles = $this->plugin->settings->GetCurrentUserRoles( $user->roles );
203
 
204
  if ( $this->plugin->settings->IsLoginSuperAdmin( $user_login ) ) {
205
  $user_roles[] = 'superadmin';
206
  }
207
 
 
 
 
 
 
 
 
 
208
  $this->plugin->alerts->Trigger(
209
  1000,
210
- array(
211
- 'Username' => $user_login,
212
- 'CurrentUserRoles' => $user_roles,
213
- ),
214
  true
215
  );
 
216
  }
217
 
218
  /**
@@ -408,6 +413,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
408
  array(
409
  'Attempts' => 1,
410
  'Username' => $username,
 
411
  'CurrentUserRoles' => $user_roles,
412
  )
413
  );
@@ -499,16 +505,27 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
499
  * @param string $username - Username.
500
  */
501
  public function EventLoginBlocked( $username ) {
502
- $user = get_user_by( 'login', $username );
503
- $user_roles = $this->plugin->settings->GetCurrentUserRoles( $user->roles );
 
 
 
 
 
 
 
504
 
 
 
505
  if ( $this->plugin->settings->IsLoginSuperAdmin( $username ) ) {
506
  $user_roles[] = 'superadmin';
507
  }
 
 
508
  $this->plugin->alerts->Trigger(
509
  1004,
510
  array(
511
- 'Username' => $username,
512
  'CurrentUserRoles' => $user_roles,
513
  ),
514
  true
46
  * Listening to events using WP hooks.
47
  */
48
  public function HookEvents() {
49
+ add_action( 'set_auth_cookie', array( $this, 'EventLogin' ), 10, 6 );
50
  add_action( 'wp_logout', array( $this, 'EventLogout' ), 5 );
51
  add_action( 'password_reset', array( $this, 'EventPasswordReset' ), 10, 2 );
52
  add_action( 'wp_login_failed', array( $this, 'EventLoginFailure' ) );
146
  /**
147
  * Event Login.
148
  *
149
+ * TODO: update params doc block to match the new hook it's attached to.
 
150
  */
151
+ public function EventLogin( $auth_cookie, $expire, $expiration, $user_id, $scheme, $token ) {
152
  // Get global POST array.
153
  $post_array = filter_input_array( INPUT_POST );
154
 
174
  && $post_array['current_user_password'] !== $post_array['user_password'] // If current & new password don't match.
175
  && $post_array['user_password'] === $post_array['confirm_user_password'] ) { // And new & confirm password are same then.
176
  // Get user.
177
+ $user = get_user_by( 'id', $user_id );
 
 
178
 
179
  // Log user changed password alert.
180
  if ( ! empty( $user ) ) {
192
  return; // Return.
193
  }
194
 
195
+ $user = get_user_by( 'id', $user_id );
196
+ // bail early if we did not get a user object.
197
+ if ( ! is_a( $user, '\WP_User' ) ) {
198
+ return;
199
  }
200
+ $user_login = $user->data->user_login;
201
  $user_roles = $this->plugin->settings->GetCurrentUserRoles( $user->roles );
202
 
203
  if ( $this->plugin->settings->IsLoginSuperAdmin( $user_login ) ) {
204
  $user_roles[] = 'superadmin';
205
  }
206
 
207
+ $alert_data = array(
208
+ 'Username' => $user_login,
209
+ 'CurrentUserRoles' => $user_roles,
210
+ );
211
+ if ( class_exists( 'WSAL_UserSessions_Helpers' ) ) {
212
+ $alert_data['SessionID'] = WSAL_UserSessions_Helpers::hash_token( $token );
213
+ }
214
+
215
  $this->plugin->alerts->Trigger(
216
  1000,
217
+ $alert_data,
 
 
 
218
  true
219
  );
220
+
221
  }
222
 
223
  /**
413
  array(
414
  'Attempts' => 1,
415
  'Username' => $username,
416
+ 'LogFileText' => '',
417
  'CurrentUserRoles' => $user_roles,
418
  )
419
  );
505
  * @param string $username - Username.
506
  */
507
  public function EventLoginBlocked( $username ) {
508
+ // try get the user object first by login and then by email.
509
+ $user = get_user_by( 'login', $username );
510
+ if ( ! $user ) {
511
+ $user = get_user_by( 'email', $username );
512
+ }
513
+ // bail early if we could not get a WP_User.
514
+ if ( ! is_a( $user, '\WP_User' ) ) {
515
+ return;
516
+ }
517
 
518
+ // get the users roles.
519
+ $user_roles = $this->plugin->settings->GetCurrentUserRoles( $user->roles );
520
  if ( $this->plugin->settings->IsLoginSuperAdmin( $username ) ) {
521
  $user_roles[] = 'superadmin';
522
  }
523
+
524
+ // record a login blocked event.
525
  $this->plugin->alerts->Trigger(
526
  1004,
527
  array(
528
+ 'Username' => $user->user_login,
529
  'CurrentUserRoles' => $user_roles,
530
  ),
531
  true
classes/Sensors/Request.php CHANGED
@@ -42,16 +42,17 @@ class WSAL_Sensors_Request extends WSAL_AbstractSensor {
42
  */
43
  public function EventShutdown() {
44
  // Filter global arrays for security.
45
- $post_array = filter_input_array( INPUT_POST );
46
  $server_array = filter_input_array( INPUT_SERVER );
47
 
48
- $upload_dir = wp_upload_dir();
49
- $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/';
50
- if ( ! $this->CheckDirectory( $uploads_dir_path ) ) {
51
- wp_mkdir_p( $uploads_dir_path );
 
52
  }
53
 
54
- $file = $uploads_dir_path . 'Request.log.php';
55
 
56
  $request_method = isset( $server_array['REQUEST_METHOD'] ) ? $server_array['REQUEST_METHOD'] : false;
57
  $request_uri = isset( $server_array['REQUEST_URI'] ) ? $server_array['REQUEST_URI'] : false;
42
  */
43
  public function EventShutdown() {
44
  // Filter global arrays for security.
45
+ $post_array = filter_input_array( INPUT_POST );
46
  $server_array = filter_input_array( INPUT_SERVER );
47
 
48
+ // get the custom logging path from settings.
49
+ $custom_logging_path = $this->plugin->options_helper->get_logging_path();
50
+
51
+ if ( ! $this->CheckDirectory( $custom_logging_path ) ) {
52
+ wp_mkdir_p( $custom_logging_path );
53
  }
54
 
55
+ $file = $custom_logging_path . 'Request.log.php';
56
 
57
  $request_method = isset( $server_array['REQUEST_METHOD'] ) ? $server_array['REQUEST_METHOD'] : false;
58
  $request_uri = isset( $server_array['REQUEST_URI'] ) ? $server_array['REQUEST_URI'] : false;
classes/Sensors/System.php CHANGED
@@ -66,20 +66,23 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
66
 
67
  add_filter( 'template_redirect', array( $this, 'Event404' ) );
68
 
69
- // Get WP upload directory.
70
- $upload_dir = wp_upload_dir();
71
-
72
- $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/404s/';
73
- if ( ! $this->CheckDirectory( $uploads_dir_path ) ) {
74
- wp_mkdir_p( $uploads_dir_path );
 
 
 
75
  }
76
 
77
  // Directory for logged in users log files.
78
- $user_upload_path = trailingslashit( $upload_dir['basedir'] . '/wp-security-audit-log/404s/users/' );
79
  $this->remove_sub_directories( $user_upload_path ); // Remove it.
80
 
81
  // Directory for visitor log files.
82
- $visitor_upload_path = trailingslashit( $upload_dir['basedir'] . '/wp-security-audit-log/404s/visitors/' );
83
  $this->remove_sub_directories( $visitor_upload_path ); // Remove it.
84
 
85
 
@@ -541,18 +544,18 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
541
  * Purge log files older than one month.
542
  */
543
  public function LogFilesPruning() {
544
- if ( $this->plugin->GetGlobalOption( 'purge-404-log', 'off' ) == 'on' ) {
545
- $upload_dir = wp_upload_dir();
546
- $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/404s/';
547
- if ( is_dir( $uploads_dir_path ) ) {
548
- if ( $handle = opendir( $uploads_dir_path ) ) {
549
  while ( false !== ( $entry = readdir( $handle ) ) ) {
550
  if ( '.' != $entry && '..' != $entry ) {
551
- if ( strpos( $entry, '6007' ) && file_exists( $uploads_dir_path . $entry ) ) {
552
- $modified = filemtime( $uploads_dir_path . $entry );
553
  if ( $modified < strtotime( '-4 weeks' ) ) {
554
  // Delete file.
555
- unlink( $uploads_dir_path . $entry );
556
  }
557
  }
558
  }
@@ -561,18 +564,18 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
561
  }
562
  }
563
  }
564
- if ( 'on' == $this->plugin->GetGlobalOption( 'purge-visitor-404-log', 'off' ) ) {
565
- $upload_dir = wp_upload_dir();
566
- $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/404s/';
567
- if ( is_dir( $uploads_dir_path ) ) {
568
- if ( $handle = opendir( $uploads_dir_path ) ) {
569
  while ( false !== ( $entry = readdir( $handle ) ) ) {
570
  if ( $entry != '.' && $entry != '..' ) {
571
- if ( strpos( $entry, '6023' ) && file_exists( $uploads_dir_path . $entry ) ) {
572
- $modified = filemtime( $uploads_dir_path . $entry );
573
  if ( $modified < strtotime( '-4 weeks' ) ) {
574
  // Delete file.
575
- unlink( $uploads_dir_path . $entry );
576
  }
577
  }
578
  }
@@ -723,9 +726,9 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
723
  private function WriteLog( $attempts, $ip, $username = '', $logged_in = true, $url = null ) {
724
  $name_file = null;
725
 
726
- if ( $logged_in && 'on' === $this->plugin->GetGlobalOption( 'log-404', 'off' ) ) {
727
  // Get option to log referrer.
728
- $log_referrer = $this->plugin->GetGlobalOption( 'log-404-referrer' );
729
 
730
  // Check localhost.
731
  if ( '127.0.0.1' == $ip || '::1' == $ip ) {
@@ -764,15 +767,23 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
764
  $username = $username . '_';
765
  }
766
 
767
- $upload_dir = wp_upload_dir();
768
- $uploads_url = trailingslashit( $upload_dir['baseurl'] ) . 'wp-security-audit-log/404s/';
769
- $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/404s/';
 
 
 
 
 
 
 
 
770
 
771
  // Check directory.
772
- if ( $this->CheckDirectory( $uploads_dir_path ) ) {
773
  $filename = '6007_' . date( 'Ymd' ) . '.log';
774
- $fp = $uploads_dir_path . $filename;
775
- $name_file = $uploads_url . $filename;
776
  if ( ! $file = fopen( $fp, 'a' ) ) {
777
  $i = 1;
778
  $file_opened = false;
@@ -781,14 +792,14 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
781
  if ( ! file_exists( $fp2 ) ) {
782
  if ( $file = fopen( $fp2, 'a' ) ) {
783
  $file_opened = true;
784
- $name_file = $uploads_url . substr( $name_file, 0, -4 ) . '_' . $i . '.log';
785
  }
786
  } else {
787
- $latest_filename = $this->GetLastModified( $uploads_dir_path, $filename );
788
- $fp_last = $uploads_dir_path . $latest_filename;
789
  if ( $file = fopen( $fp_last, 'a' ) ) {
790
  $file_opened = true;
791
- $name_file = $uploads_url . $latest_filename;
792
  }
793
  }
794
  $i++;
66
 
67
  add_filter( 'template_redirect', array( $this, 'Event404' ) );
68
 
69
+ // get the logging location.
70
+ $custom_logging_path_base = $this->plugin->options_helper->get_logging_path();
71
+ $custom_logging_path = $custom_logging_path_base . '404s/';
72
+ if ( ! $this->CheckDirectory( $custom_logging_path ) ) {
73
+ $dir_made = wp_mkdir_p( $custom_logging_path );
74
+ if ( $dir_made ) {
75
+ // make an empty index.php in the directory.
76
+ @file_put_contents( $custom_logging_path . 'index.php', '<?php // Silence is golden' );
77
+ }
78
  }
79
 
80
  // Directory for logged in users log files.
81
+ $user_upload_path = trailingslashit( $custom_logging_path_base . '404s/users/' );
82
  $this->remove_sub_directories( $user_upload_path ); // Remove it.
83
 
84
  // Directory for visitor log files.
85
+ $visitor_upload_path = trailingslashit( $custom_logging_path_base . '/404s/visitors/' );
86
  $this->remove_sub_directories( $visitor_upload_path ); // Remove it.
87
 
88
 
544
  * Purge log files older than one month.
545
  */
546
  public function LogFilesPruning() {
547
+ if ( $this->plugin->options_helper->get_option_value( 'purge-404-log', 'off' ) == 'on' ) {
548
+ $custom_logging_path = $this->plugin->options_helper->get_logging_path();
549
+ $custom_logging_path = $custom_logging_path . '404s/';
550
+ if ( is_dir( $custom_logging_path ) ) {
551
+ if ( $handle = opendir( $custom_logging_path ) ) {
552
  while ( false !== ( $entry = readdir( $handle ) ) ) {
553
  if ( '.' != $entry && '..' != $entry ) {
554
+ if ( strpos( $entry, '6007' ) && file_exists( $custom_logging_path . $entry ) ) {
555
+ $modified = filemtime( $custom_logging_path . $entry );
556
  if ( $modified < strtotime( '-4 weeks' ) ) {
557
  // Delete file.
558
+ unlink( $custom_logging_path . $entry );
559
  }
560
  }
561
  }
564
  }
565
  }
566
  }
567
+ if ( 'on' == $this->plugin->options_helper->get_option_value( 'purge-visitor-404-log', 'off' ) ) {
568
+ $custom_logging_path = $this->plugin->options_helper->get_logging_path();
569
+ $custom_logging_path = $custom_logging_path . '404s/';
570
+ if ( is_dir( $custom_logging_path ) ) {
571
+ if ( $handle = opendir( $custom_logging_path ) ) {
572
  while ( false !== ( $entry = readdir( $handle ) ) ) {
573
  if ( $entry != '.' && $entry != '..' ) {
574
+ if ( strpos( $entry, '6023' ) && file_exists( $custom_logging_path . $entry ) ) {
575
+ $modified = filemtime( $custom_logging_path . $entry );
576
  if ( $modified < strtotime( '-4 weeks' ) ) {
577
  // Delete file.
578
+ unlink( $custom_logging_path . $entry );
579
  }
580
  }
581
  }
726
  private function WriteLog( $attempts, $ip, $username = '', $logged_in = true, $url = null ) {
727
  $name_file = null;
728
 
729
+ if ( $logged_in && 'on' === $this->plugin->options_helper->get_option_value( 'log-404', 'off' ) ) {
730
  // Get option to log referrer.
731
+ $log_referrer = $this->plugin->options_helper->get_option_value( 'log-404-referrer' );
732
 
733
  // Check localhost.
734
  if ( '127.0.0.1' == $ip || '::1' == $ip ) {
767
  $username = $username . '_';
768
  }
769
 
770
+ // get the custom logging path from settings.
771
+ $custom_logging_path = $this->plugin->options_helper->get_logging_path() . '404s/';
772
+ $custom_logging_url = $this->plugin->options_helper->get_logging_url() . '404s/';
773
+
774
+ if ( ! $this->CheckDirectory( $custom_logging_path ) ) {
775
+ $dir_made = wp_mkdir_p( $custom_logging_path );
776
+ if ( $dir_made ) {
777
+ // make an empty index.php in the directory.
778
+ @file_put_contents( $custom_logging_path . 'index.php', '<?php // Silence is golden' );
779
+ }
780
+ }
781
 
782
  // Check directory.
783
+ if ( $this->CheckDirectory( $custom_logging_path ) ) {
784
  $filename = '6007_' . date( 'Ymd' ) . '.log';
785
+ $fp = $custom_logging_path . $filename;
786
+ $name_file = $custom_logging_url . $filename;
787
  if ( ! $file = fopen( $fp, 'a' ) ) {
788
  $i = 1;
789
  $file_opened = false;
792
  if ( ! file_exists( $fp2 ) ) {
793
  if ( $file = fopen( $fp2, 'a' ) ) {
794
  $file_opened = true;
795
+ $name_file = $custom_logging_url . substr( $name_file, 0, -4 ) . '_' . $i . '.log';
796
  }
797
  } else {
798
+ $latest_filename = $this->GetLastModified( $custom_logging_path, $filename );
799
+ $fp_last = $custom_logging_path . $latest_filename;
800
  if ( $file = fopen( $fp_last, 'a' ) ) {
801
  $file_opened = true;
802
+ $name_file = $custom_logging_url . $latest_filename;
803
  }
804
  }
805
  $i++;
classes/Sensors/WooCommerce.php CHANGED
@@ -248,8 +248,9 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
248
  if ( 'product' === $post->post_type ) {
249
  if (
250
  ( 'auto-draft' === $this->_old_post->post_status && 'draft' === $post->post_status ) // Saving draft.
251
- || ( 'draft' === $this->_old_post->post_status && 'publish' === $post->post_status ) // Publishing post.
252
- ) {
 
253
  $this->EventCreation( $this->_old_post, $post );
254
  } else {
255
  // Delay the checks to accomodate WooCommerce inline product changes.
248
  if ( 'product' === $post->post_type ) {
249
  if (
250
  ( 'auto-draft' === $this->_old_post->post_status && 'draft' === $post->post_status ) // Saving draft.
251
+ || ( 'draft' === $this->_old_post->post_status && 'publish' === $post->post_status ) // Publishing post.
252
+ || ( 'auto-draft' === $this->_old_post->post_status && 'publish' === $post->post_status )
253
+ ) {
254
  $this->EventCreation( $this->_old_post, $post );
255
  } else {
256
  // Delay the checks to accomodate WooCommerce inline product changes.
classes/Settings.php CHANGED
@@ -32,6 +32,8 @@ class WSAL_Settings {
32
  const OPT_DEV_BACKTRACE_LOG = 'b';
33
  const ERROR_CODE_INVALID_IP = 901;
34
 
 
 
35
  /**
36
  * List of Site Admins.
37
  *
@@ -145,6 +147,10 @@ class WSAL_Settings {
145
  */
146
  public function __construct( WpSecurityAuditLog $plugin ) {
147
  $this->_plugin = $plugin;
 
 
 
 
148
  add_action( 'deactivated_plugin', array( $this, 'reset_stealth_mode' ), 10, 1 );
149
  }
150
 
@@ -1220,11 +1226,11 @@ class WSAL_Settings {
1220
  }
1221
 
1222
  public function Set404LogLimit( $value ) {
1223
- $this->_plugin->SetGlobalOption( 'log-404-limit', abs( $value ) );
1224
  }
1225
 
1226
  public function Get404LogLimit() {
1227
- return $this->_plugin->GetGlobalOption( 'log-404-limit', 99 );
1228
  }
1229
 
1230
  /**
@@ -1234,7 +1240,7 @@ class WSAL_Settings {
1234
  * @since 2.6.3
1235
  */
1236
  public function SetVisitor404LogLimit( $value ) {
1237
- $this->_plugin->SetGlobalOption( 'log-visitor-404-limit', abs( $value ) );
1238
  }
1239
 
1240
  /**
@@ -1243,7 +1249,7 @@ class WSAL_Settings {
1243
  * @since 2.6.3
1244
  */
1245
  public function GetVisitor404LogLimit() {
1246
- return $this->_plugin->GetGlobalOption( 'log-visitor-404-limit', 99 );
1247
  }
1248
 
1249
  /**
@@ -1254,9 +1260,9 @@ class WSAL_Settings {
1254
  */
1255
  public function set_failed_login_limit( $value ) {
1256
  if ( ! empty( $value ) ) {
1257
- $this->_plugin->SetGlobalOption( 'log-failed-login-limit', abs( $value ) );
1258
  } else {
1259
- $this->_plugin->SetGlobalOption( 'log-failed-login-limit', -1 );
1260
  }
1261
  }
1262
 
@@ -1266,7 +1272,7 @@ class WSAL_Settings {
1266
  * @since 2.6.3
1267
  */
1268
  public function get_failed_login_limit() {
1269
- return $this->_plugin->GetGlobalOption( 'log-failed-login-limit', 10 );
1270
  }
1271
 
1272
  /**
@@ -1277,9 +1283,9 @@ class WSAL_Settings {
1277
  */
1278
  public function set_visitor_failed_login_limit( $value ) {
1279
  if ( ! empty( $value ) ) {
1280
- $this->_plugin->SetGlobalOption( 'log-visitor-failed-login-limit', abs( $value ) );
1281
  } else {
1282
- $this->_plugin->SetGlobalOption( 'log-visitor-failed-login-limit', -1 );
1283
  }
1284
  }
1285
 
@@ -1289,7 +1295,7 @@ class WSAL_Settings {
1289
  * @since 2.6.3
1290
  */
1291
  public function get_visitor_failed_login_limit() {
1292
- return $this->_plugin->GetGlobalOption( 'log-visitor-failed-login-limit', 10 );
1293
  }
1294
 
1295
  public function IsArchivingEnabled() {
32
  const OPT_DEV_BACKTRACE_LOG = 'b';
33
  const ERROR_CODE_INVALID_IP = 901;
34
 
35
+ const DEFAULT_LOGGING_DIR = '/wp-content/uploads/wp-security-audit-log/';
36
+
37
  /**
38
  * List of Site Admins.
39
  *
147
  */
148
  public function __construct( WpSecurityAuditLog $plugin ) {
149
  $this->_plugin = $plugin;
150
+ // some settings here may be called before the options helper is setup.
151
+ if ( ! isset( $this->_plugin->options_helper ) ) {
152
+ $this->_plugin->include_options_helper();
153
+ }
154
  add_action( 'deactivated_plugin', array( $this, 'reset_stealth_mode' ), 10, 1 );
155
  }
156
 
1226
  }
1227
 
1228
  public function Set404LogLimit( $value ) {
1229
+ $this->_plugin->options_helper->set_option_value( 'log-404-limit', abs( $value ) );
1230
  }
1231
 
1232
  public function Get404LogLimit() {
1233
+ return $this->_plugin->options_helper->get_option_value( 'log-404-limit', 99 );
1234
  }
1235
 
1236
  /**
1240
  * @since 2.6.3
1241
  */
1242
  public function SetVisitor404LogLimit( $value ) {
1243
+ $this->_plugin->options_helper->set_option_value( 'log-visitor-404-limit', abs( $value ) );
1244
  }
1245
 
1246
  /**
1249
  * @since 2.6.3
1250
  */
1251
  public function GetVisitor404LogLimit() {
1252
+ return $this->_plugin->options_helper->get_option_value( 'log-visitor-404-limit', 99 );
1253
  }
1254
 
1255
  /**
1260
  */
1261
  public function set_failed_login_limit( $value ) {
1262
  if ( ! empty( $value ) ) {
1263
+ $this->_plugin->options_helper->set_option_value( 'log-failed-login-limit', abs( $value ) );
1264
  } else {
1265
+ $this->_plugin->options_helper->set_option_value( 'log-failed-login-limit', -1 );
1266
  }
1267
  }
1268
 
1272
  * @since 2.6.3
1273
  */
1274
  public function get_failed_login_limit() {
1275
+ return $this->_plugin->options_helper->get_option_value( 'log-failed-login-limit', 10 );
1276
  }
1277
 
1278
  /**
1283
  */
1284
  public function set_visitor_failed_login_limit( $value ) {
1285
  if ( ! empty( $value ) ) {
1286
+ $this->_plugin->options_helper->set_option_value( 'log-visitor-failed-login-limit', abs( $value ) );
1287
  } else {
1288
+ $this->_plugin->options_helper->set_option_value( 'log-visitor-failed-login-limit', -1 );
1289
  }
1290
  }
1291
 
1295
  * @since 2.6.3
1296
  */
1297
  public function get_visitor_failed_login_limit() {
1298
+ return $this->_plugin->options_helper->get_option_value( 'log-visitor-failed-login-limit', 10 );
1299
  }
1300
 
1301
  public function IsArchivingEnabled() {
classes/Update/Task/MoveSettingsToOptionsTable.php CHANGED
@@ -58,6 +58,7 @@ class MoveSettingsToOptionstable {
58
  $this->wsal = $wsal;
59
  $this->prefix = $prefix;
60
  add_filter( 'wsal_update_move_settings', array( $this, 'settings_to_move_4_0_3' ) );
 
61
  }
62
 
63
  /**
@@ -97,6 +98,10 @@ class MoveSettingsToOptionstable {
97
 
98
  // Loop through array of options to move to WP options table.
99
  foreach ( $settings_to_move as $setting ) {
 
 
 
 
100
  $value = $this->wsal->options_helper->get_option_value( $setting );
101
  // to prevent override of already migrated data we will first check
102
  // if option value exists in the standard options table.
@@ -126,7 +131,7 @@ class MoveSettingsToOptionstable {
126
  * @return array
127
  */
128
  public function settings_to_move_4_0_3( $settings ) {
129
- if ( \version_compare( $this->old_version, '4.0.2', '>=' ) && \version_compare( $this->new_version, '4.0.3', '<=' ) ) {
130
  // settings moved in this version update.
131
  $settings = array_merge(
132
  $settings,
@@ -148,4 +153,38 @@ class MoveSettingsToOptionstable {
148
  return $settings;
149
  }
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  }
58
  $this->wsal = $wsal;
59
  $this->prefix = $prefix;
60
  add_filter( 'wsal_update_move_settings', array( $this, 'settings_to_move_4_0_3' ) );
61
+ add_filter( 'wsal_update_move_settings', array( $this, 'settings_to_move_4_0_1' ) );
62
  }
63
 
64
  /**
98
 
99
  // Loop through array of options to move to WP options table.
100
  foreach ( $settings_to_move as $setting ) {
101
+ // the wsal- prefix needs stripped from this option.
102
+ if ( false !== ( 'wsal-' === substr( $setting, 0, 5 ) ) ) {
103
+ $setting = str_replace( 'wsal-', '', $setting );
104
+ }
105
  $value = $this->wsal->options_helper->get_option_value( $setting );
106
  // to prevent override of already migrated data we will first check
107
  // if option value exists in the standard options table.
131
  * @return array
132
  */
133
  public function settings_to_move_4_0_3( $settings ) {
134
+ if ( \version_compare( $this->old_version, '4.0.2', '>=' ) && \version_compare( $this->old_version, '4.0.3', '<' ) ) {
135
  // settings moved in this version update.
136
  $settings = array_merge(
137
  $settings,
153
  return $settings;
154
  }
155
 
156
+ /**
157
+ * Filters in a list of settings to move in the 4.0.3 update.
158
+ *
159
+ * NOTE: Should fire if coming from before 4.0.1 to 4.0.3 or later.
160
+ *
161
+ * @method settings_to_move_4_0_3
162
+ * @since 4.1.0
163
+ * @param array $settings An array of settings to move.
164
+ * @return array
165
+ */
166
+ public function settings_to_move_4_0_1( $settings ) {
167
+ if ( \version_compare( $this->old_version, '4.0.2', '>=' ) && \version_compare( $this->old_version, '4.1.0', '<' ) ) {
168
+ // settings moved in this version update.
169
+ $settings = array_merge(
170
+ $settings,
171
+ array(
172
+ 'log-404',
173
+ 'log-404-limit',
174
+ 'log-404-referrer',
175
+ 'purge-404-log',
176
+ 'wsal-setup-modal-dismissed',
177
+ 'log-visitor-failed-login-limit',
178
+ 'log-failed-login-limit',
179
+ 'log-visitor-404-limit',
180
+ 'log-visitor-404-referrer',
181
+ 'purge-visitor-404-log',
182
+ 'log-visitor-404',
183
+ )
184
+ );
185
+ }
186
+ // Return an array of all the setting we are wanting moved.
187
+ return $settings;
188
+ }
189
+
190
  }
classes/ViewManager.php CHANGED
@@ -122,7 +122,7 @@ class WSAL_ViewManager {
122
  // Initialize setup wizard.
123
  if (
124
  'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-complete', 'no' )
125
- || 'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-modal-dismissed', 'no' )
126
  ) {
127
  new WSAL_Views_SetupWizard( $plugin );
128
  }
@@ -390,7 +390,7 @@ class WSAL_ViewManager {
390
  }
391
  break;
392
  case 'wsal-loginusers':
393
- if ( class_exists( 'WSAL_User_Management_Plugin' ) ) {
394
  $not_show = true;
395
  }
396
  break;
122
  // Initialize setup wizard.
123
  if (
124
  'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-complete', 'no' )
125
+ || 'no' === $this->_plugin->options_helper->get_option_value( 'setup-modal-dismissed', 'no' )
126
  ) {
127
  new WSAL_Views_SetupWizard( $plugin );
128
  }
390
  }
391
  break;
392
  case 'wsal-loginusers':
393
+ if ( class_exists( 'WSAL_UserSessions_Plugin' ) ) {
394
  $not_show = true;
395
  }
396
  break;
classes/Views/AuditLog.php CHANGED
@@ -131,7 +131,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
131
  && ! class_exists( 'WSAL_Ext_Plugin' )
132
  && ! class_exists( 'WSAL_Rep_Plugin' )
133
  && ! class_exists( 'WSAL_SearchExtension' )
134
- && ! class_exists( 'WSAL_User_Management_Plugin' )
135
  && 'anonymous' !== get_site_option( 'wsal_freemius_state', 'anonymous' ) // Anonymous mode option.
136
  ) {
137
  $get_transient_fn = $this->_plugin->IsMultisite() ? 'get_site_transient' : 'get_transient'; // Check for multisite.
@@ -574,7 +574,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
574
  <?php
575
  if (
576
  'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-complete', 'no' )
577
- && 'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-modal-dismissed', 'no' )
578
  ) :
579
  ?>
580
  <div data-remodal-id="wsal-setup-modal">
@@ -590,16 +590,16 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
590
  wsal_setup_modal.remodal().open();
591
 
592
  jQuery(document).on('confirmation', wsal_setup_modal, function () {
593
- <?php $this->_plugin->SetGlobalOption( 'wsal-setup-modal-dismissed', 'yes' ); ?>
594
  window.location = '<?php echo esc_url( add_query_arg( 'page', 'wsal-setup', admin_url( 'index.php' ) ) ); ?>';
595
  });
596
 
597
  jQuery(document).on('cancellation', wsal_setup_modal, function () {
598
- <?php $this->_plugin->SetGlobalOption( 'wsal-setup-modal-dismissed', 'yes' ); ?>
599
  });
600
 
601
  jQuery(document).on('closed', wsal_setup_modal, function () {
602
- <?php $this->_plugin->SetGlobalOption( 'wsal-setup-modal-dismissed', 'yes' ); ?>
603
  });
604
  });
605
  </script>
@@ -1068,7 +1068,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1068
  // Don't display notice if the wizard notice is showing.
1069
  if (
1070
  'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-complete', 'no' )
1071
- && 'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-modal-dismissed', 'no' )
1072
  ) {
1073
  return;
1074
  }
131
  && ! class_exists( 'WSAL_Ext_Plugin' )
132
  && ! class_exists( 'WSAL_Rep_Plugin' )
133
  && ! class_exists( 'WSAL_SearchExtension' )
134
+ && ! class_exists( 'WSAL_UserSessions_Plugin' )
135
  && 'anonymous' !== get_site_option( 'wsal_freemius_state', 'anonymous' ) // Anonymous mode option.
136
  ) {
137
  $get_transient_fn = $this->_plugin->IsMultisite() ? 'get_site_transient' : 'get_transient'; // Check for multisite.
574
  <?php
575
  if (
576
  'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-complete', 'no' )
577
+ && 'no' === $this->_plugin->options_helper->get_option_value( 'setup-modal-dismissed', 'no' )
578
  ) :
579
  ?>
580
  <div data-remodal-id="wsal-setup-modal">
590
  wsal_setup_modal.remodal().open();
591
 
592
  jQuery(document).on('confirmation', wsal_setup_modal, function () {
593
+ <?php $this->_plugin->options_helper->set_option_value( 'setup-modal-dismissed', 'yes' ); ?>
594
  window.location = '<?php echo esc_url( add_query_arg( 'page', 'wsal-setup', admin_url( 'index.php' ) ) ); ?>';
595
  });
596
 
597
  jQuery(document).on('cancellation', wsal_setup_modal, function () {
598
+ <?php $this->_plugin->options_helper->set_option_value( 'setup-modal-dismissed', 'yes' ); ?>
599
  });
600
 
601
  jQuery(document).on('closed', wsal_setup_modal, function () {
602
+ <?php $this->_plugin->options_helper->set_option_value( 'setup-modal-dismissed', 'yes' ); ?>
603
  });
604
  });
605
  </script>
1068
  // Don't display notice if the wizard notice is showing.
1069
  if (
1070
  'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-complete', 'no' )
1071
+ && 'no' === $this->_plugin->options_helper->get_option_value( 'setup-modal-dismissed', 'no' )
1072
  ) {
1073
  return;
1074
  }
classes/Views/Settings.php CHANGED
@@ -2035,6 +2035,36 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
2035
  <?php echo sprintf( __( 'If you have any questions <a href="https://wpactivitylog.com/contact/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">contact us</a>.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?>
2036
  </p>
2037
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2038
  <h3><?php esc_html_e( 'Troubleshooting setting: Keep a debug log of all the requests this website receives', 'wp-security-audit-log' ); ?></h3>
2039
  <p class="description"><?php esc_html_e( 'Only enable the request log on testing, staging and development website. Never enable logging on a live website unless instructed to do so. Enabling request logging on a live website may degrade the performance of the website.', 'wp-security-audit-log' ); ?></p>
2040
  <table class="form-table wsal-tab">
@@ -2201,6 +2231,33 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
2201
  } else {
2202
  $this->_plugin->settings->deactivate_mainwp_child_stealth_mode();
2203
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2204
  }
2205
 
2206
  /**
2035
  <?php echo sprintf( __( 'If you have any questions <a href="https://wpactivitylog.com/contact/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">contact us</a>.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?>
2036
  </p>
2037
 
2038
+ <h3><?php esc_html_e( 'Where do you want to save the log files?', 'wp-security-audit-log' ); ?></h3>
2039
+ <p class="description"><?php esc_html_e( 'The plugin uses a number of log files. It uses these log files to keep a log of 1) requests to non-existing URLs from logged in users (event ID 6007) and non-logged in users (6023), 2) the request log. Use the below setting to save the log files in different location. Please specify the relative path.', 'wp-security-audit-log' ); ?></p>
2040
+ <table class="form-table wsal-tab">
2041
+ <tbody>
2042
+ <!-- custom log directory -->
2043
+ <tr>
2044
+ <th><label><?php esc_html_e( 'Log files location', 'wp-security-audit-log' ); ?></label></th>
2045
+ <td>
2046
+ <fieldset>
2047
+ <?php $location = $this->_plugin->options_helper->get_option_value( 'custom-logging-dir', \WSAL_Settings::DEFAULT_LOGGING_DIR ); ?>
2048
+ <label for="wsal-custom-logs-dir">
2049
+ <input type="text" name="wsal-custom-logs-dir" id="wsal-custom-logs-dir"
2050
+ value="<?php echo esc_attr( $location ); ?>">
2051
+ </label>
2052
+ <p class="description">
2053
+ <?php
2054
+ echo wp_kses(
2055
+ __( '<strong>Note:</strong> Enter a path from the root of your website: eg "/wp-content/uploads/wp-security-audit-log/".' ),
2056
+ $this->_plugin->allowed_html_tags
2057
+ );
2058
+ ?>
2059
+ </p>
2060
+ </fieldset>
2061
+ </td>
2062
+ </tr>
2063
+ <!-- / custom log directory -->
2064
+ </tbody>
2065
+ </table>
2066
+
2067
+
2068
  <h3><?php esc_html_e( 'Troubleshooting setting: Keep a debug log of all the requests this website receives', 'wp-security-audit-log' ); ?></h3>
2069
  <p class="description"><?php esc_html_e( 'Only enable the request log on testing, staging and development website. Never enable logging on a live website unless instructed to do so. Enabling request logging on a live website may degrade the performance of the website.', 'wp-security-audit-log' ); ?></p>
2070
  <table class="form-table wsal-tab">
2231
  } else {
2232
  $this->_plugin->settings->deactivate_mainwp_child_stealth_mode();
2233
  }
2234
+
2235
+ $custom_logging_dir = ( isset( $post_array['wsal-custom-logs-dir'] ) ) ? filter_var( $post_array['wsal-custom-logs-dir'], FILTER_SANITIZE_STRING ) : WSAL_Settings::DEFAULT_LOGGING_DIR;
2236
+ if ( ! empty( $custom_logging_dir ) ) {
2237
+ $custom_logging_path = trailingslashit( get_home_path() ) . ltrim( trailingslashit( $custom_logging_dir ), '/' );
2238
+ if ( ! is_dir( $custom_logging_path ) || ! is_readable( $custom_logging_path ) || ! is_writable( $custom_logging_path ) ) {
2239
+ if ( is_writable( dirname( $custom_logging_path ) ) ) {
2240
+ $dir_made = wp_mkdir_p( $custom_logging_path );
2241
+ if ( $dir_made ) {
2242
+ // make an empty index.php in the directory.
2243
+ @file_put_contents( $custom_logging_path . 'index.php', '<?php // Silence is golden' );
2244
+ }
2245
+ }
2246
+
2247
+ // if the directory was not made then we will try revert or use default value.
2248
+ if ( ! $dir_made ) {
2249
+ // revert to old/default.
2250
+ $previous_path = $this->_plugin->options_helper->get_option_value( 'custom-logging-dir', false );
2251
+ if ( ! false === $previous_path && is_writable( $previous_path ) ) {
2252
+ $custom_logging_dir = $previous_path;
2253
+ } else {
2254
+ $custom_logging_dir = WSAL_Settings::DEFAULT_LOGGING_DIR;
2255
+ }
2256
+ }
2257
+ }
2258
+ // save.
2259
+ $this->_plugin->options_helper->set_option_value( 'custom-logging-dir', $custom_logging_dir );
2260
+ }
2261
  }
2262
 
2263
  /**
classes/Views/SetupWizard.php CHANGED
@@ -123,7 +123,21 @@ final class WSAL_Views_SetupWizard {
123
  * Add setup admin page.
124
  */
125
  public function admin_menus() {
 
126
  add_dashboard_page( '', '', 'manage_options', 'wsal-setup', '' );
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  }
128
 
129
  /**
@@ -414,8 +428,8 @@ final class WSAL_Views_SetupWizard {
414
  */
415
  private function wsal_step_welcome() {
416
  // Dismiss the setup modal on audit log.
417
- if ( 'no' === $this->wsal->GetGlobalOption( 'wsal-setup-modal-dismissed', 'no' ) ) {
418
- $this->wsal->SetGlobalOption( 'wsal-setup-modal-dismissed', 'yes' );
419
  }
420
  ?>
421
  <p><?php esc_html_e( 'This wizard helps you configure the basic plugin settings. All these settings can be changed at a later stage from the plugin settings.', 'wp-security-audit-log' ); ?></p>
123
  * Add setup admin page.
124
  */
125
  public function admin_menus() {
126
+ // this is an empty title because we do not want it to display.
127
  add_dashboard_page( '', '', 'manage_options', 'wsal-setup', '' );
128
+ // hide it via CSS as well so screen readers pass over it.
129
+ add_action(
130
+ 'admin_head',
131
+ function() {
132
+ ?>
133
+ <style>
134
+ .wp-submenu a[href="wsal-setup"]{
135
+ display: none !important;
136
+ }
137
+ </style>
138
+ <?php
139
+ }
140
+ );
141
  }
142
 
143
  /**
428
  */
429
  private function wsal_step_welcome() {
430
  // Dismiss the setup modal on audit log.
431
+ if ( 'no' === $this->wsal->options_helper->get_option_value( 'setup-modal-dismissed', 'no' ) ) {
432
+ $this->wsal->options_helper->set_option_value( 'setup-modal-dismissed', 'yes' );
433
  }
434
  ?>
435
  <p><?php esc_html_e( 'This wizard helps you configure the basic plugin settings. All these settings can be changed at a later stage from the plugin settings.', 'wp-security-audit-log' ); ?></p>
classes/Views/ToggleAlerts.php CHANGED
@@ -98,13 +98,13 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
98
  // Save the disabled events.
99
  $this->_plugin->alerts->SetDisabledAlerts( $disabled );
100
 
101
- $this->_plugin->SetGlobalOption( 'log-404', isset( $post_array['log_404'] ) ? 'on' : 'off' );
102
- $this->_plugin->SetGlobalOption( 'purge-404-log', isset( $post_array['purge_log'] ) ? 'on' : 'off' );
103
- $this->_plugin->SetGlobalOption( 'log-404-referrer', isset( $post_array['log_404_referrer'] ) ? 'on' : 'off' );
104
 
105
- $this->_plugin->SetGlobalOption( 'log-visitor-404', isset( $post_array['log_visitor_404'] ) ? 'on' : 'off' );
106
- $this->_plugin->SetGlobalOption( 'purge-visitor-404-log', isset( $post_array['purge_visitor_log'] ) ? 'on' : 'off' );
107
- $this->_plugin->SetGlobalOption( 'log-visitor-404-referrer', isset( $post_array['log_visitor_404_referrer'] ) ? 'on' : 'off' );
108
  $this->_plugin->SetGlobalOption( 'wc-all-stock-changes', isset( $post_array['wc_all_stock_changes'] ) ? 'on' : 'off' );
109
 
110
  $this->_plugin->settings->Set404LogLimit( $post_array['user_404Limit'] );
@@ -467,9 +467,9 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
467
  </tr>
468
  <?php
469
  if ( 6007 === $alert->type ) {
470
- $log_404 = $this->_plugin->GetGlobalOption( 'log-404' );
471
- $purge_log = $this->_plugin->GetGlobalOption( 'purge-404-log' );
472
- $log_404_referrer = $this->_plugin->GetGlobalOption( 'log-404-referrer', 'on' );
473
  ?>
474
  <tr>
475
  <td></td>
@@ -500,7 +500,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
500
  <?php
501
  }
502
  if ( 1002 === $alert->type ) {
503
- $log_failed_login_limit = (int) $this->_plugin->GetGlobalOption( 'log-failed-login-limit', 10 );
504
  $log_failed_login_limit = ( -1 === $log_failed_login_limit ) ? '0' : $log_failed_login_limit;
505
  ?>
506
  <tr>
@@ -513,7 +513,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
513
  <?php
514
  }
515
  if ( 1003 === $alert->type ) {
516
- $log_visitor_failed_login_limit = (int) $this->_plugin->GetGlobalOption( 'log-visitor-failed-login-limit', 10 );
517
  $log_visitor_failed_login_limit = ( -1 === $log_visitor_failed_login_limit ) ? '0' : $log_visitor_failed_login_limit;
518
  ?>
519
  <tr>
@@ -613,9 +613,9 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
613
  </td>
614
  </tr>
615
  <?php
616
- $log_visitor_404 = $this->_plugin->GetGlobalOption( 'log-visitor-404' );
617
- $purge_visitor_log = $this->_plugin->GetGlobalOption( 'purge-visitor-404-log' );
618
- $log_visitor_404_referrer = $this->_plugin->GetGlobalOption( 'log-visitor-404-referrer', 'on' );
619
  ?>
620
  <tr>
621
  <td><input name="log_visitor_404" type="checkbox" class="check_visitor_log" value="1" <?php checked( $log_visitor_404, 'on' ); ?> /></td>
98
  // Save the disabled events.
99
  $this->_plugin->alerts->SetDisabledAlerts( $disabled );
100
 
101
+ $this->_plugin->options_helper->set_option_value( 'log-404', isset( $post_array['log_404'] ) ? 'on' : 'off' );
102
+ $this->_plugin->options_helper->set_option_value( 'purge-404-log', isset( $post_array['purge_log'] ) ? 'on' : 'off' );
103
+ $this->_plugin->options_helper->set_option_value( 'log-404-referrer', isset( $post_array['log_404_referrer'] ) ? 'on' : 'off' );
104
 
105
+ $this->_plugin->options_helper->set_option_value( 'log-visitor-404', isset( $post_array['log_visitor_404'] ) ? 'on' : 'off' );
106
+ $this->_plugin->options_helper->set_option_value( 'purge-visitor-404-log', isset( $post_array['purge_visitor_log'] ) ? 'on' : 'off' );
107
+ $this->_plugin->options_helper->set_option_value( 'log-visitor-404-referrer', isset( $post_array['log_visitor_404_referrer'] ) ? 'on' : 'off' );
108
  $this->_plugin->SetGlobalOption( 'wc-all-stock-changes', isset( $post_array['wc_all_stock_changes'] ) ? 'on' : 'off' );
109
 
110
  $this->_plugin->settings->Set404LogLimit( $post_array['user_404Limit'] );
467
  </tr>
468
  <?php
469
  if ( 6007 === $alert->type ) {
470
+ $log_404 = $this->_plugin->options_helper->get_option_value( 'log-404' );
471
+ $purge_log = $this->_plugin->options_helper->get_option_value( 'purge-404-log' );
472
+ $log_404_referrer = $this->_plugin->options_helper->get_option_value( 'log-404-referrer', 'on' );
473
  ?>
474
  <tr>
475
  <td></td>
500
  <?php
501
  }
502
  if ( 1002 === $alert->type ) {
503
+ $log_failed_login_limit = (int) $this->_plugin->options_helper->get_option_value( 'log-failed-login-limit', 10 );
504
  $log_failed_login_limit = ( -1 === $log_failed_login_limit ) ? '0' : $log_failed_login_limit;
505
  ?>
506
  <tr>
513
  <?php
514
  }
515
  if ( 1003 === $alert->type ) {
516
+ $log_visitor_failed_login_limit = (int) $this->_plugin->options_helper->get_option_value( 'log-visitor-failed-login-limit', 10 );
517
  $log_visitor_failed_login_limit = ( -1 === $log_visitor_failed_login_limit ) ? '0' : $log_visitor_failed_login_limit;
518
  ?>
519
  <tr>
613
  </td>
614
  </tr>
615
  <?php
616
+ $log_visitor_404 = $this->_plugin->options_helper->get_option_value( 'log-visitor-404' );
617
+ $purge_visitor_log = $this->_plugin->options_helper->get_option_value( 'purge-visitor-404-log' );
618
+ $log_visitor_404_referrer = $this->_plugin->options_helper->get_option_value( 'log-visitor-404-referrer', 'on' );
619
  ?>
620
  <tr>
621
  <td><input name="log_visitor_404" type="checkbox" class="check_visitor_log" value="1" <?php checked( $log_visitor_404, 'on' ); ?> /></td>
css/extensions.css CHANGED
@@ -545,7 +545,7 @@ ul.premium-list li:before {
545
  .our-wordpress-plugins.side-bar {
546
  width: 30%;
547
  margin-bottom: 30px;
548
- }
549
 
550
  @media (max-width: 991px) {
551
  .our-wordpress-plugins.full ul li{
@@ -568,3 +568,4 @@ ul.premium-list li:before {
568
  margin: 0 auto 20px auto;
569
  }
570
  }
 
545
  .our-wordpress-plugins.side-bar {
546
  width: 30%;
547
  margin-bottom: 30px;
548
+ }
549
 
550
  @media (max-width: 991px) {
551
  .our-wordpress-plugins.full ul li{
568
  margin: 0 auto 20px auto;
569
  }
570
  }
571
+
css/settings.css CHANGED
@@ -84,6 +84,9 @@
84
  .wsal-tab th {
85
  /* padding-left: 20px; */
86
  }
 
 
 
87
  .wsal-tab td {
88
  padding-left: 20px;
89
  }
@@ -101,7 +104,6 @@
101
  .wsal-tab input[type=email] {
102
  display: inline-block;
103
  width: 350px;
104
- padding: 5px;
105
  margin: 0;
106
  }
107
  .wsal-tab input[type=button],
@@ -280,3 +282,7 @@ a.disabled {
280
  font-weight: 600;
281
  border: none;
282
  }
 
 
 
 
84
  .wsal-tab th {
85
  /* padding-left: 20px; */
86
  }
87
+ .wsal-tab.wsal-twilio-settings-tab th {
88
+ width: 220px;
89
+ }
90
  .wsal-tab td {
91
  padding-left: 20px;
92
  }
104
  .wsal-tab input[type=email] {
105
  display: inline-block;
106
  width: 350px;
 
107
  margin: 0;
108
  }
109
  .wsal-tab input[type=button],
282
  font-weight: 600;
283
  border: none;
284
  }
285
+
286
+ fieldset #pruning-unit {
287
+ margin-top: -2px;
288
+ }
defaults.php CHANGED
@@ -88,7 +88,7 @@ function wsaldefaults_wsal_init() {
88
  __( 'User Activity', 'wp-security-audit-log' ) => array(
89
  array( 1000, WSAL_LOW, __( 'User logged in', 'wp-security-audit-log' ), '', 'user', 'login' ),
90
  array( 1001, WSAL_LOW, __( 'User logged out', 'wp-security-audit-log' ), '', 'user', 'logout' ),
91
- array( 1002, WSAL_MEDIUM, __( 'Login failed', 'wp-security-audit-log' ), '', 'user', 'failed-login' ),
92
  array( 1003, WSAL_LOW, __( 'Login failed / non existing user', 'wp-security-audit-log' ), __( '%Attempts% failed login(s) %LineBreak% %LogFileText%', 'wp-security-audit-log' ), 'system', 'failed-login' ),
93
  array( 1004, WSAL_MEDIUM, __( 'Login blocked', 'wp-security-audit-log' ), __( 'Login blocked because other session(s) already exist for this user. %LineBreak% IP address: %ClientIP%', 'wp-security-audit-log' ), 'user', 'blocked' ),
94
  array( 1005, WSAL_LOW, __( 'User logged in with existing session(s)', 'wp-security-audit-log' ), __( 'User logged in however there are other session(s) already exist for this user. %LineBreak% IP address: %IPAddress%', 'wp-security-audit-log' ), 'user', 'login' ),
88
  __( 'User Activity', 'wp-security-audit-log' ) => array(
89
  array( 1000, WSAL_LOW, __( 'User logged in', 'wp-security-audit-log' ), '', 'user', 'login' ),
90
  array( 1001, WSAL_LOW, __( 'User logged out', 'wp-security-audit-log' ), '', 'user', 'logout' ),
91
+ array( 1002, WSAL_MEDIUM, __( 'Login failed', 'wp-security-audit-log' ), '%Attempts% failed login(s) %LineBreak% %LogFileText%', 'user', 'failed-login' ),
92
  array( 1003, WSAL_LOW, __( 'Login failed / non existing user', 'wp-security-audit-log' ), __( '%Attempts% failed login(s) %LineBreak% %LogFileText%', 'wp-security-audit-log' ), 'system', 'failed-login' ),
93
  array( 1004, WSAL_MEDIUM, __( 'Login blocked', 'wp-security-audit-log' ), __( 'Login blocked because other session(s) already exist for this user. %LineBreak% IP address: %ClientIP%', 'wp-security-audit-log' ), 'user', 'blocked' ),
94
  array( 1005, WSAL_LOW, __( 'User logged in with existing session(s)', 'wp-security-audit-log' ), __( 'User logged in however there are other session(s) already exist for this user. %LineBreak% IP address: %IPAddress%', 'wp-security-audit-log' ), 'user', 'login' ),
readme.txt CHANGED
@@ -6,7 +6,7 @@ License URI: https://www.gnu.org/licenses/gpl.html
6
  Tags: activity log, wordpress activity logs, security audit log, audit log, user tracking, security event log, audit trail, wordpress security monitor, wordpress admin, wordpress admin monitoring, user activity, admin, multisite, SMS alerts, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report, wordpress audit trail
7
  Requires at least: 3.6
8
  Tested up to: 5.4.1
9
- Stable tag: 4.0.4
10
  Requires PHP: 5.5
11
 
12
  The #1 user-rated activity log plugin. Keep a comprehensive log of the changes that happen on your site with this easy to use plugin.
@@ -204,11 +204,26 @@ Please refer to our [support pages](https://wpactivitylog.com/support/?utm_sourc
204
 
205
  == Changelog ==
206
 
207
- = 4.0.4 (2020-05-20) =
208
 
209
- Release notes: [Introducing WP Activity Log (the new name for WP Security Audit Log)](https://wpactivitylog.com/wp-security-audit-log-renamed-wp-activity-log/)
210
 
211
- * **Name Change**
212
- * In this update we renamed WP Security Audit Log to WP Activity log. No code changes are included in this release.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
  Refer to the [complete plugin changelog](https://wpactivitylog.com/support/kb/plugin-changelog/?utm_source=wordpress.org&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+repos+description) for more detailed information about what was new, improved and fixed in previous versions of the WP Activity Log plugin.
6
  Tags: activity log, wordpress activity logs, security audit log, audit log, user tracking, security event log, audit trail, wordpress security monitor, wordpress admin, wordpress admin monitoring, user activity, admin, multisite, SMS alerts, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report, wordpress audit trail
7
  Requires at least: 3.6
8
  Tested up to: 5.4.1
9
+ Stable tag: 4.1.0
10
  Requires PHP: 5.5
11
 
12
  The #1 user-rated activity log plugin. Keep a comprehensive log of the changes that happen on your site with this easy to use plugin.
204
 
205
  == Changelog ==
206
 
207
+ = 4.1.0 (2020-05-26) =
208
 
209
+ Release notes: [New session policies per user roles & other improvements](https://wpactivitylog.com/wsal-4-1/)
210
 
211
+ * **New Features**
212
+ * New [WordPress users sessions management](https://wpactivitylog.com/features/wordpress-users-sessions-management-tools/) module with configurable policies per user role.
213
+ * Setting to configure the log files location (request log file, 6007 and 6023 events).
214
+
215
+ * **Plugin Improvements**
216
+ * [Activity log reports](https://wpactivitylog.com/features/reports-wordpress-activity-log/) now support user roles which have the space character in the name.
217
+ * Removed more legacy code from the plugin (the check for encryption method).
218
+ * Removed old update scripts (for when updating from versions prior to 3.5.2).
219
+ * Moved 10 more plugin settings from the custom table to the wp_options table (performance improvement).
220
+ * Standardized the format of all placeholders in the UI (now they are all using default WordPress format).
221
+ * Removed premium only code from free edition.
222
+
223
+ * **Bug fixes**
224
+ * Scheduled daily reports included data of the last 24 hours instead of the previous day.
225
+ * Resaving the activity logs archiving settings generated errors (didn't check if connection was already setup).
226
+ * Issue with the plugin when installed on MainWP child sites ([support ticket](https://wordpress.org/support/topic/cannot-use-object-of-type-wsal_models_occurrencequery-as-array/)).
227
+ * Plugin adding Menu entry with no title (used by the wizard).
228
 
229
  Refer to the [complete plugin changelog](https://wpactivitylog.com/support/kb/plugin-changelog/?utm_source=wordpress.org&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+repos+description) for more detailed information about what was new, improved and fixed in previous versions of the WP Activity Log plugin.
sdk/wsal-freemius.php CHANGED
@@ -15,10 +15,6 @@ if ( ! defined( 'ABSPATH' ) ) {
15
 
16
  if ( file_exists( dirname( __FILE__ ) . '/freemius/start.php' ) ) {
17
 
18
- if ( WpSecurityAuditLog::is_plugin_active( 'nofs/wsal-nofs.php' ) ) {
19
- require_once WP_PLUGIN_DIR . '/nofs/wsal-nofs.php';
20
- }
21
-
22
  /**
23
  * Freemius SDK
24
  *
15
 
16
  if ( file_exists( dirname( __FILE__ ) . '/freemius/start.php' ) ) {
17
 
 
 
 
 
18
  /**
19
  * Freemius SDK
20
  *
wp-security-audit-log.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin URI: http://wpactivitylog.com/
5
  * Description: Identify WordPress security issues before they become a problem. Keep track of everything happening on your WordPress including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Activity Log generates a security alert for everything that happens on your WordPress blogs and websites. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  * Author: WP White Security
7
- * Version: 4.0.4
8
  * Text Domain: wp-security-audit-log
9
  * Author URI: http://www.wpwhitesecurity.com/
10
  * License: GPL2
@@ -46,7 +46,7 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
46
  *
47
  * @var string
48
  */
49
- public $version = '4.0.4';
50
 
51
  // Plugin constants.
52
  const PLG_CLS_PRFX = 'WSAL_';
@@ -676,7 +676,7 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
676
  case 'latest_event':
677
  // run the query and return it.
678
  $event = $this->query_for_latest_event();
679
- $event->getAdapter()->Execute( $event );
680
 
681
  // Set the return object.
682
  if ( isset( $event[0] ) ) {
@@ -800,25 +800,6 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
800
  }
801
  }
802
 
803
- /**
804
- * Method: Include extensions for premium version.
805
- *
806
- * @since 2.7.0
807
- */
808
- public function include_extensions__premium_only() {
809
- /**
810
- * Class for extensions managment.
811
- *
812
- * @since 2.7.0
813
- */
814
- if ( file_exists( WSAL_BASE_DIR . '/extensions/class-wsal-extension-manager.php' ) ) {
815
- require_once WSAL_BASE_DIR . '/extensions/class-wsal-extension-manager.php';
816
- }
817
-
818
- // Initiate the extensions manager.
819
- $this->extensions = new WSAL_Extension_Manager( $this );
820
- }
821
-
822
  /**
823
  * Customize Freemius connect message for new users.
824
  *
4
  * Plugin URI: http://wpactivitylog.com/
5
  * Description: Identify WordPress security issues before they become a problem. Keep track of everything happening on your WordPress including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Activity Log generates a security alert for everything that happens on your WordPress blogs and websites. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  * Author: WP White Security
7
+ * Version: 4.1.0
8
  * Text Domain: wp-security-audit-log
9
  * Author URI: http://www.wpwhitesecurity.com/
10
  * License: GPL2
46
  *
47
  * @var string
48
  */
49
+ public $version = '4.1.0';
50
 
51
  // Plugin constants.
52
  const PLG_CLS_PRFX = 'WSAL_';
676
  case 'latest_event':
677
  // run the query and return it.
678
  $event = $this->query_for_latest_event();
679
+ $event = $event->getAdapter()->Execute( $event );
680
 
681
  // Set the return object.
682
  if ( isset( $event[0] ) ) {
800
  }
801
  }
802
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
803
  /**
804
  * Customize Freemius connect message for new users.
805
  *