WP Security Audit Log - Version 1.3.2

Version Description

(2014-12-16) = * New Features and Options * Plugin automatically retrieves user's originating IP address even if WordPress is installed behind a reverse proxy, web application firewall or load balancer. For more information refer to WP Security Audit Log, Reverse Proxies and WAFs * New option to omit internal IP addresses from being reported in the WordPress security audit log

  • Removed Functionality

    • The sandbox was removed from the plugin. If you need to use the sandbox for troubleshooting and tested contact us since we migrated it to a standalone extension.
  • Bug Fixes

    • Fixed a bug where site administrators where not able to view the WordPress security alerts for their sites in a WordPress multisite installation
    • Improved some SQL queries as reported in this support ticket
    • Fixed an issue with alerts pruning (when pruning was set by number of alerts the plugin was pruning all alerts)
Download this release

Release Info

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

Code changes from version 1.3.1 to 1.3.2

classes/AlertManager.php CHANGED
@@ -223,7 +223,9 @@ final class WSAL_AlertManager {
223
  */
224
  protected function Log($type, $data = array()){
225
  if(!isset($data['ClientIP']))
226
- $data['ClientIP'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
 
 
227
  if(!isset($data['UserAgent']))
228
  $data['UserAgent'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
229
  if(!isset($data['Username']) && !isset($data['CurrentUserID']))
223
  */
224
  protected function Log($type, $data = array()){
225
  if(!isset($data['ClientIP']))
226
+ $data['ClientIP'] = $this->plugin->settings->GetMainClientIP();
227
+ if(!isset($data['OtherIPs']) && $this->plugin->settings->IsMainIPFromProxy())
228
+ $data['OtherIPs'] = $this->plugin->settings->GetClientIPs();
229
  if(!isset($data['UserAgent']))
230
  $data['UserAgent'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
231
  if(!isset($data['Username']) && !isset($data['CurrentUserID']))
classes/AuditLogListView.php CHANGED
@@ -183,7 +183,17 @@ class WSAL_AuditLogListView extends WP_List_Table {
183
  }
184
  return $image . $uhtml . '<br/>' . $roles;
185
  case 'scip':
186
- return !is_null($item->GetSourceIP()) ? esc_html($item->GetSourceIP()) : '<i>unknown</i>';
 
 
 
 
 
 
 
 
 
 
187
  case 'site':
188
  $info = get_blog_details($item->site_id, true);
189
  return !$info ? ('Unknown Site '.$item->site_id)
183
  }
184
  return $image . $uhtml . '<br/>' . $roles;
185
  case 'scip':
186
+ $scip = $item->GetSourceIP();
187
+ $oips = array(); //$item->GetOtherIPs();
188
+ // if there's no IP...
189
+ if (is_null($scip) || $scip == '') return '<i>unknown</i>';
190
+ // if there's only one IP...
191
+ if (count($oips) < 2) return esc_html($scip);
192
+ // if there are many IPs...
193
+ $html = esc_html($scip) . ' <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
194
+ foreach($oips as $ip)if($scip!=$ip)$html .= '<div>' . $ip . '</div>';
195
+ $html .= '</div>';
196
+ return $html;
197
  case 'site':
198
  $info = get_blog_details($item->site_id, true);
199
  return !$info ? ('Unknown Site '.$item->site_id)
classes/DB/ActiveRecord.php CHANGED
@@ -57,9 +57,9 @@ abstract class WSAL_DB_ActiveRecord {
57
  $sql .= $key . ' DOUBLE NOT NULL,' . PHP_EOL;
58
  break;
59
  case is_string($copy->$key):
60
- $maxlenght = $key . '_maxlength';
61
- if(property_exists($class, $maxlenght)){
62
- $sql .= $key . ' VARCHAR(' . intval($class::$$maxlenght) . ') NOT NULL,' . PHP_EOL;
63
  }else{
64
  $sql .= $key . ' TEXT NOT NULL,' . PHP_EOL;
65
  }
57
  $sql .= $key . ' DOUBLE NOT NULL,' . PHP_EOL;
58
  break;
59
  case is_string($copy->$key):
60
+ $maxlength = $key . '_maxlength';
61
+ if(property_exists($class, $maxlength)){
62
+ $sql .= $key . ' VARCHAR(' . intval($class::$$maxlength) . ') NOT NULL,' . PHP_EOL;
63
  }else{
64
  $sql .= $key . ' TEXT NOT NULL,' . PHP_EOL;
65
  }
classes/DB/Occurrence.php CHANGED
@@ -176,6 +176,16 @@ class WSAL_DB_Occurrence extends WSAL_DB_ActiveRecord {
176
  return $this->GetMetaValue('ClientIP', '');
177
  }
178
 
 
 
 
 
 
 
 
 
 
 
179
  /**
180
  * @return array Array of user roles.
181
  */
176
  return $this->GetMetaValue('ClientIP', '');
177
  }
178
 
179
+ /**
180
+ * @return string IP address of request (from proxies etc).
181
+ */
182
+ public function GetOtherIPs(){
183
+ $result = array();
184
+ $data = (array)$this->GetMetaValue('OtherIPs', array());
185
+ foreach ($data as $ips) foreach($ips as $ip) $result[] = $ip;
186
+ return array_unique($result);
187
+ }
188
+
189
  /**
190
  * @return array Array of user roles.
191
  */
classes/Loggers/Database.php CHANGED
@@ -1,16 +1,16 @@
1
  <?php
2
 
3
  class WSAL_Loggers_Database extends WSAL_AbstractLogger {
4
-
5
  public function __construct(WpSecurityAuditLog $plugin) {
6
  parent::__construct($plugin);
7
  $plugin->AddCleanupHook(array($this, 'CleanUp'));
8
  }
9
-
10
  public function Log($type, $data = array(), $date = null, $siteid = null, $migrated = false) {
11
  // is this a php alert, and if so, are we logging such alerts?
12
  if ($type < 0010 && !$this->plugin->settings->IsPhpErrorLoggingEnabled()) return;
13
-
14
  // create new occurrence
15
  $occ = new WSAL_DB_Occurrence();
16
  $occ->is_migrated = $migrated;
@@ -19,45 +19,53 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
19
  $occ->site_id = !is_null($siteid) ? $siteid
20
  : (function_exists('get_current_blog_id') ? get_current_blog_id() : 0);
21
  $occ->Save();
22
-
23
  // set up meta data
24
  $occ->SetMeta($data);
25
  }
26
-
27
  public function CleanUp() {
28
  $now = current_time('timestamp');
29
  $max_sdate = $this->plugin->settings->GetPruningDate();
30
  $max_count = $this->plugin->settings->GetPruningLimit();
31
  $is_date_e = $this->plugin->settings->IsPruningDateEnabled();
32
  $is_limt_e = $this->plugin->settings->IsPruningLimitEnabled();
33
-
34
- $max_stamp = $now - (strtotime($max_sdate) - $now);
 
 
 
35
  $cnt_items = WSAL_DB_Occurrence::Count();
 
 
 
 
 
 
 
36
  $max_items = max(($cnt_items - $max_count) + 1, 0);
37
-
38
- if (!$is_date_e && !$is_limt_e) return; // pruning disabled
39
-
40
  $query = new WSAL_DB_OccurrenceQuery('WSAL_DB_Occurrence');
41
  $query->order[] = 'created_on ASC';
42
-
43
- if ($is_date_e) $query->Where('created_on < %d', array($max_stamp));
44
  if ($is_limt_e) $query->length = (int)$max_items;
45
-
46
  $count = $query->Count();
47
  if (!$count) return; // nothing to delete
48
-
49
  // delete data
50
  $query->Delete();
51
-
52
  // keep track of what we're doing
53
  $this->plugin->alerts->Trigger(0003, array(
54
  'Message' => 'Running system cleanup.',
55
  'Query SQL' => $query->GetSql(),
56
  'Query Args' => $query->GetArgs(),
57
  ), true);
58
-
59
  // notify system
60
  do_action('wsal_prune', $count, vsprintf($query->GetSql(), $query->GetArgs()));
61
  }
62
-
63
  }
1
  <?php
2
 
3
  class WSAL_Loggers_Database extends WSAL_AbstractLogger {
4
+
5
  public function __construct(WpSecurityAuditLog $plugin) {
6
  parent::__construct($plugin);
7
  $plugin->AddCleanupHook(array($this, 'CleanUp'));
8
  }
9
+
10
  public function Log($type, $data = array(), $date = null, $siteid = null, $migrated = false) {
11
  // is this a php alert, and if so, are we logging such alerts?
12
  if ($type < 0010 && !$this->plugin->settings->IsPhpErrorLoggingEnabled()) return;
13
+
14
  // create new occurrence
15
  $occ = new WSAL_DB_Occurrence();
16
  $occ->is_migrated = $migrated;
19
  $occ->site_id = !is_null($siteid) ? $siteid
20
  : (function_exists('get_current_blog_id') ? get_current_blog_id() : 0);
21
  $occ->Save();
22
+
23
  // set up meta data
24
  $occ->SetMeta($data);
25
  }
26
+
27
  public function CleanUp() {
28
  $now = current_time('timestamp');
29
  $max_sdate = $this->plugin->settings->GetPruningDate();
30
  $max_count = $this->plugin->settings->GetPruningLimit();
31
  $is_date_e = $this->plugin->settings->IsPruningDateEnabled();
32
  $is_limt_e = $this->plugin->settings->IsPruningLimitEnabled();
33
+
34
+ if (!$is_date_e && !$is_limt_e) {
35
+ return;
36
+ } // pruning disabled
37
+
38
  $cnt_items = WSAL_DB_Occurrence::Count();
39
+
40
+ // Check if there is something to delete
41
+ if($is_limt_e && ($cnt_items < $max_count)){
42
+ return;
43
+ }
44
+
45
+ $max_stamp = $now - (strtotime($max_sdate) - $now);
46
  $max_items = max(($cnt_items - $max_count) + 1, 0);
47
+
 
 
48
  $query = new WSAL_DB_OccurrenceQuery('WSAL_DB_Occurrence');
49
  $query->order[] = 'created_on ASC';
50
+
51
+ if ($is_date_e) $query->Where('created_on < ' . intval($max_stamp), array());
52
  if ($is_limt_e) $query->length = (int)$max_items;
53
+
54
  $count = $query->Count();
55
  if (!$count) return; // nothing to delete
56
+
57
  // delete data
58
  $query->Delete();
59
+
60
  // keep track of what we're doing
61
  $this->plugin->alerts->Trigger(0003, array(
62
  'Message' => 'Running system cleanup.',
63
  'Query SQL' => $query->GetSql(),
64
  'Query Args' => $query->GetArgs(),
65
  ), true);
66
+
67
  // notify system
68
  do_action('wsal_prune', $count, vsprintf($query->GetSql(), $query->GetArgs()));
69
  }
70
+
71
  }
classes/Sensors/LogInOut.php CHANGED
@@ -58,7 +58,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
58
 
59
  list($y, $m, $d) = explode('-', date('Y-m-d'));
60
 
61
- $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
62
  $tt1 = new WSAL_DB_Occurrence();
63
  $tt2 = new WSAL_DB_Meta();
64
 
58
 
59
  list($y, $m, $d) = explode('-', date('Y-m-d'));
60
 
61
+ $ip = $this->plugin->settings->GetMainClientIP();
62
  $tt1 = new WSAL_DB_Occurrence();
63
  $tt2 = new WSAL_DB_Meta();
64
 
classes/Settings.php CHANGED
@@ -5,26 +5,27 @@ class WSAL_Settings {
5
  * @var WpSecurityAuditLog
6
  */
7
  protected $_plugin;
8
-
9
  public function __construct(WpSecurityAuditLog $plugin){
10
  $this->_plugin = $plugin;
11
  }
12
 
 
 
13
  const OPT_DEV_DATA_INSPECTOR = 'd';
14
  const OPT_DEV_PHP_ERRORS = 'p';
15
  const OPT_DEV_REQUEST_LOG = 'r';
16
- const OPT_DEV_SANDBOX_PAGE = 's';
17
  const OPT_DEV_BACKTRACE_LOG = 'b';
18
-
19
  protected $_devoption = null;
20
-
21
  /**
22
  * @return array Array of developer options to be enabled by default.
23
  */
24
  public function GetDefaultDevOptions(){
25
  return array();
26
  }
27
-
28
  /**
29
  * Returns whether a developer option is enabled or not.
30
  * @param string $option See self::OPT_DEV_* constants.
@@ -40,14 +41,14 @@ class WSAL_Settings {
40
  }
41
  return in_array($option, $this->_devoption);
42
  }
43
-
44
  /**
45
  * @return boolean Whether any developer option has been enabled or not.
46
  */
47
  public function IsAnyDevOptionEnabled(){
48
  return !!$this->_plugin->GetGlobalOption('dev-options', null);
49
  }
50
-
51
  /**
52
  * Sets whether a developer option is enabled or not.
53
  * @param string $option See self::OPT_DEV_* constants.
@@ -68,7 +69,7 @@ class WSAL_Settings {
68
  implode(',', $this->_devoption)
69
  );
70
  }
71
-
72
  /**
73
  * Remove all enabled developer options.
74
  */
@@ -76,35 +77,28 @@ class WSAL_Settings {
76
  $this->_devoption = array();
77
  $this->_plugin->SetGlobalOption('dev-options', '');
78
  }
79
-
80
  /**
81
  * @return boolean Whether to enable data inspector or not.
82
  */
83
  public function IsDataInspectorEnabled(){
84
  return $this->IsDevOptionEnabled(self::OPT_DEV_DATA_INSPECTOR);
85
  }
86
-
87
  /**
88
  * @return boolean Whether to PHP error logging or not.
89
  */
90
  public function IsPhpErrorLoggingEnabled(){
91
  return $this->IsDevOptionEnabled(self::OPT_DEV_PHP_ERRORS);
92
  }
93
-
94
  /**
95
  * @return boolean Whether to log requests to file or not.
96
  */
97
  public function IsRequestLoggingEnabled(){
98
  return $this->IsDevOptionEnabled(self::OPT_DEV_REQUEST_LOG);
99
  }
100
-
101
- /**
102
- * @return boolean Whether PHP sandbox page is enabled or not.
103
- */
104
- public function IsSandboxPageEnabled(){
105
- return $this->IsDevOptionEnabled(self::OPT_DEV_SANDBOX_PAGE);
106
- }
107
-
108
  /**
109
  * @return boolean Whether to store debug backtrace for PHP alerts or not.
110
  */
@@ -112,34 +106,36 @@ class WSAL_Settings {
112
  return $this->IsDevOptionEnabled(self::OPT_DEV_BACKTRACE_LOG);
113
  }
114
 
 
 
115
  /**
116
  * @return boolean Whether dashboard widgets are enabled or not.
117
  */
118
  public function IsWidgetsEnabled(){
119
  return !$this->_plugin->GetGlobalOption('disable-widgets');
120
  }
121
-
122
  /**
123
  * @param boolean $newvalue Whether dashboard widgets are enabled or not.
124
  */
125
  public function SetWidgetsEnabled($newvalue){
126
  $this->_plugin->SetGlobalOption('disable-widgets', !$newvalue);
127
  }
128
-
129
  /**
130
  * @return boolean Whether alerts in audit log view refresh automatically or not.
131
  */
132
  public function IsRefreshAlertsEnabled(){
133
  return !$this->_plugin->GetGlobalOption('disable-refresh');
134
  }
135
-
136
  /**
137
  * @param boolean $newvalue Whether alerts in audit log view refresh automatically or not.
138
  */
139
  public function SetRefreshAlertsEnabled($newvalue){
140
  $this->_plugin->SetGlobalOption('disable-refresh', !$newvalue);
141
  }
142
-
143
  /**
144
  * @return int Maximum number of alerts to show in dashboard widget.
145
  */
@@ -147,22 +143,24 @@ class WSAL_Settings {
147
  return 5;
148
  }
149
 
 
 
150
  /**
151
  * @return int The maximum number of alerts allowable.
152
  */
153
  public function GetMaxAllowedAlerts(){
154
  return 5000;
155
  }
156
-
157
  /**
158
  * @return string The default pruning date.
159
  */
160
  public function GetDefaultPruningDate(){
161
  return '1 month';
162
  }
163
-
164
  protected $_pruning = 0;
165
-
166
  /**
167
  * @return string The current pruning date.
168
  */
@@ -174,7 +172,7 @@ class WSAL_Settings {
174
  }
175
  return $this->_pruning;
176
  }
177
-
178
  /**
179
  * @param string $newvalue The new pruning date.
180
  */
@@ -184,7 +182,7 @@ class WSAL_Settings {
184
  $this->_pruning = $newvalue;
185
  }
186
  }
187
-
188
  /**
189
  * @return integer Maximum number of alerts to keep.
190
  */
@@ -192,7 +190,7 @@ class WSAL_Settings {
192
  $val = (int)$this->_plugin->GetGlobalOption('pruning-limit');
193
  return $val ? $val : $this->GetMaxAllowedAlerts();
194
  }
195
-
196
  /**
197
  * @param integer $newvalue The new maximum number of alerts.
198
  */
@@ -200,37 +198,39 @@ class WSAL_Settings {
200
  $newvalue = max(/*min(*/(int)$newvalue/*, $this->GetMaxAllowedAlerts())*/, 1);
201
  $this->_plugin->SetGlobalOption('pruning-limit', $newvalue);
202
  }
203
-
204
  public function SetPruningDateEnabled($enabled){
205
  $this->_plugin->SetGlobalOption('pruning-date-e', $enabled);
206
  }
207
-
208
  public function SetPruningLimitEnabled($enabled){
209
  $this->_plugin->SetGlobalOption('pruning-limit-e', $enabled);
210
  }
211
-
212
  public function IsPruningDateEnabled(){
213
  return $this->_plugin->GetGlobalOption('pruning-date-e', true);
214
  }
215
-
216
  public function IsPruningLimitEnabled(){
217
  return $this->_plugin->GetGlobalOption('pruning-limit-e', true);
218
  }
219
-
220
  public function IsRestrictAdmins(){
221
  return $this->_plugin->GetGlobalOption('restrict-admins', false);
222
  }
223
-
224
  public function SetRestrictAdmins($enable){
225
  $this->_plugin->SetGlobalOption('restrict-admins', (bool)$enable);
226
  }
227
 
 
 
228
  protected $_disabled = null;
229
-
230
  public function GetDefaultDisabledAlerts(){
231
  return array(); //array(0000, 0003, 0005);
232
  }
233
-
234
  /**
235
  * @return array IDs of disabled alerts.
236
  */
@@ -243,7 +243,7 @@ class WSAL_Settings {
243
  }
244
  return $this->_disabled;
245
  }
246
-
247
  /**
248
  * @param array $types IDs alerts to disable.
249
  */
@@ -251,49 +251,59 @@ class WSAL_Settings {
251
  $this->_disabled = array_unique(array_map('intval', $types));
252
  $this->_plugin->SetGlobalOption('disabled-alerts', implode(',', $this->_disabled));
253
  }
 
 
 
 
 
 
 
 
254
 
255
- protected $_viewers = null;
256
 
 
 
257
  public function SetAllowedPluginViewers($usersOrRoles){
258
  $this->_viewers = $usersOrRoles;
259
  $this->_plugin->SetGlobalOption('plugin-viewers', implode(',', $this->_viewers));
260
  }
261
-
262
  public function GetAllowedPluginViewers(){
263
  if(is_null($this->_viewers)){
264
  $this->_viewers = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-viewers'))));
265
  }
266
  return $this->_viewers;
267
  }
268
-
269
  protected $_editors = null;
270
-
271
  public function SetAllowedPluginEditors($usersOrRoles){
272
  $this->_editors = $usersOrRoles;
273
  $this->_plugin->SetGlobalOption('plugin-editors', implode(',', $this->_editors));
274
  }
275
-
276
  public function GetAllowedPluginEditors(){
277
  if(is_null($this->_editors)){
278
  $this->_editors = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-editors'))));
279
  }
280
  return $this->_editors;
281
  }
282
-
283
  protected $_perpage = null;
284
-
285
  public function SetViewPerPage($newvalue){
286
  $this->_perpage = max($newvalue, 1);
287
  $this->_plugin->SetGlobalOption('items-per-page', $this->_perpage);
288
  }
289
-
290
  public function GetViewPerPage(){
291
  if(is_null($this->_perpage)){
292
  $this->_perpage = (int)$this->_plugin->GetGlobalOption('items-per-page', 10);
293
  }
294
  return $this->_perpage;
295
  }
296
-
297
  /**
298
  * @param string $action Type of action, either 'view' or 'edit'.
299
  * @return boolean If user has access or not.
@@ -301,14 +311,14 @@ class WSAL_Settings {
301
  public function CurrentUserCan($action){
302
  return $this->UserCan(wp_get_current_user(), $action);
303
  }
304
-
305
  /**
306
  * @return string[] List of superadmin usernames.
307
  */
308
  protected function GetSuperAdmins(){
309
  return $this->_plugin->IsMultisite() ? get_super_admins() : array();
310
  }
311
-
312
  /**
313
  * @return string[] List of admin usernames.
314
  */
@@ -316,8 +326,7 @@ class WSAL_Settings {
316
  if($this->_plugin->IsMultisite()){
317
  // see: https://gist.github.com/1508426/65785a15b8638d43a9905effb59e4d97319ef8f8
318
  global $wpdb;
319
- $cap = get_current_blog_id();
320
- $cap = ($cap < 2) ? 'wp_capabilities' : "wp_{$cap}_capabilities";
321
  $sql = "SELECT DISTINCT $wpdb->users.user_login"
322
  . " FROM $wpdb->users"
323
  . " INNER JOIN $wpdb->usermeta ON ($wpdb->users.ID = $wpdb->usermeta.user_id )"
@@ -331,7 +340,7 @@ class WSAL_Settings {
331
  return $result;
332
  }
333
  }
334
-
335
  /**
336
  * Returns access tokens for a particular action.
337
  * @param string $action Type of action.
@@ -339,7 +348,7 @@ class WSAL_Settings {
339
  */
340
  public function GetAccessTokens($action){
341
  $allowed = array();
342
-
343
  switch($action){
344
  case 'view':
345
  $allowed = $this->GetAllowedPluginViewers();
@@ -360,7 +369,7 @@ class WSAL_Settings {
360
  default:
361
  throw new Exception('Unknown action "'.$action.'".');
362
  }
363
-
364
  if (!$this->IsRestrictAdmins()) {
365
  if(is_multisite()){
366
  $allowed = array_merge($allowed, get_super_admins());
@@ -368,10 +377,10 @@ class WSAL_Settings {
368
  $allowed[] = 'administrator';
369
  }
370
  }
371
-
372
  return array_unique($allowed);
373
  }
374
-
375
  /**
376
  * @param integer|WP_user $user User object to check.
377
  * @param string $action Type of action, either 'view' or 'edit'.
@@ -379,88 +388,152 @@ class WSAL_Settings {
379
  */
380
  public function UserCan($user, $action){
381
  if(is_int($user))$user = get_userdata($user);
382
-
383
  $allowed = $this->GetAccessTokens($action);
384
-
385
  $check = array_merge(
386
  $user->roles,
387
  array($user->user_login)
388
  );
389
-
390
  foreach($check as $item){
391
  if(in_array($item, $allowed)){
392
  return true;
393
  }
394
  }
395
-
396
  return false;
397
  }
398
-
399
  public function GetCurrentUserRoles($baseRoles = null){
400
  if ($baseRoles == null) $baseRoles = wp_get_current_user()->roles;
401
  if (function_exists('is_super_admin') && is_super_admin()) $baseRoles[] = 'superadmin';
402
  return $baseRoles;
403
  }
404
 
405
- public function IsIncognito(){
406
- return $this->_plugin->GetGlobalOption('hide-plugin');
407
- }
408
-
409
- public function SetIncognito($enabled){
410
- return $this->_plugin->SetGlobalOption('hide-plugin', $enabled);
411
- }
412
 
 
 
413
  public function GetLicenses(){
414
  return $this->_plugin->GetGlobalOption('licenses');
415
  }
416
-
417
  public function GetLicense($name){
418
  $data = $this->GetLicenses();
419
  $name = sanitize_key(basename($name));
420
  return isset($data[$name]) ? $data[$name] : array();
421
  }
422
-
423
  public function SetLicenses($data){
424
  $this->_plugin->SetGlobalOption('licenses', $data);
425
  }
426
-
427
  public function GetLicenseKey($name){
428
  $data = $this->GetLicense($name);
429
  return isset($data['key']) ? $data['key'] : '';
430
  }
431
-
432
  public function GetLicenseStatus($name){
433
  $data = $this->GetLicense($name);
434
  return isset($data['sts']) ? $data['sts'] : '';
435
  }
436
-
437
  public function GetLicenseErrors($name){
438
  $data = $this->GetLicense($name);
439
  return isset($data['err']) ? $data['err'] : '';
440
  }
441
-
442
  public function SetLicenseKey($name, $key){
443
  $data = $this->GetLicenses();
444
  if (!isset($data[$name])) $data[$name] = array();
445
  $data[$name]['key'] = $key;
446
  $this->SetLicenses($data);
447
  }
448
-
449
  public function SetLicenseStatus($name, $status){
450
  $data = $this->GetLicenses();
451
  if (!isset($data[$name])) $data[$name] = array();
452
  $data[$name]['sts'] = $status;
453
  $this->SetLicenses($data);
454
  }
455
-
456
  public function SetLicenseErrors($name, $errors){
457
  $data = $this->GetLicenses();
458
  if (!isset($data[$name])) $data[$name] = array();
459
  $data[$name]['err'] = $errors;
460
  $this->SetLicenses($data);
461
  }
462
-
463
  public function ClearLicenses(){
464
  $this->SetLicenses(array());
465
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
  }
5
  * @var WpSecurityAuditLog
6
  */
7
  protected $_plugin;
8
+
9
  public function __construct(WpSecurityAuditLog $plugin){
10
  $this->_plugin = $plugin;
11
  }
12
 
13
+ // <editor-fold desc="Developer Options">
14
+
15
  const OPT_DEV_DATA_INSPECTOR = 'd';
16
  const OPT_DEV_PHP_ERRORS = 'p';
17
  const OPT_DEV_REQUEST_LOG = 'r';
 
18
  const OPT_DEV_BACKTRACE_LOG = 'b';
19
+
20
  protected $_devoption = null;
21
+
22
  /**
23
  * @return array Array of developer options to be enabled by default.
24
  */
25
  public function GetDefaultDevOptions(){
26
  return array();
27
  }
28
+
29
  /**
30
  * Returns whether a developer option is enabled or not.
31
  * @param string $option See self::OPT_DEV_* constants.
41
  }
42
  return in_array($option, $this->_devoption);
43
  }
44
+
45
  /**
46
  * @return boolean Whether any developer option has been enabled or not.
47
  */
48
  public function IsAnyDevOptionEnabled(){
49
  return !!$this->_plugin->GetGlobalOption('dev-options', null);
50
  }
51
+
52
  /**
53
  * Sets whether a developer option is enabled or not.
54
  * @param string $option See self::OPT_DEV_* constants.
69
  implode(',', $this->_devoption)
70
  );
71
  }
72
+
73
  /**
74
  * Remove all enabled developer options.
75
  */
77
  $this->_devoption = array();
78
  $this->_plugin->SetGlobalOption('dev-options', '');
79
  }
80
+
81
  /**
82
  * @return boolean Whether to enable data inspector or not.
83
  */
84
  public function IsDataInspectorEnabled(){
85
  return $this->IsDevOptionEnabled(self::OPT_DEV_DATA_INSPECTOR);
86
  }
87
+
88
  /**
89
  * @return boolean Whether to PHP error logging or not.
90
  */
91
  public function IsPhpErrorLoggingEnabled(){
92
  return $this->IsDevOptionEnabled(self::OPT_DEV_PHP_ERRORS);
93
  }
94
+
95
  /**
96
  * @return boolean Whether to log requests to file or not.
97
  */
98
  public function IsRequestLoggingEnabled(){
99
  return $this->IsDevOptionEnabled(self::OPT_DEV_REQUEST_LOG);
100
  }
101
+
 
 
 
 
 
 
 
102
  /**
103
  * @return boolean Whether to store debug backtrace for PHP alerts or not.
104
  */
106
  return $this->IsDevOptionEnabled(self::OPT_DEV_BACKTRACE_LOG);
107
  }
108
 
109
+ // </editor-fold>
110
+
111
  /**
112
  * @return boolean Whether dashboard widgets are enabled or not.
113
  */
114
  public function IsWidgetsEnabled(){
115
  return !$this->_plugin->GetGlobalOption('disable-widgets');
116
  }
117
+
118
  /**
119
  * @param boolean $newvalue Whether dashboard widgets are enabled or not.
120
  */
121
  public function SetWidgetsEnabled($newvalue){
122
  $this->_plugin->SetGlobalOption('disable-widgets', !$newvalue);
123
  }
124
+
125
  /**
126
  * @return boolean Whether alerts in audit log view refresh automatically or not.
127
  */
128
  public function IsRefreshAlertsEnabled(){
129
  return !$this->_plugin->GetGlobalOption('disable-refresh');
130
  }
131
+
132
  /**
133
  * @param boolean $newvalue Whether alerts in audit log view refresh automatically or not.
134
  */
135
  public function SetRefreshAlertsEnabled($newvalue){
136
  $this->_plugin->SetGlobalOption('disable-refresh', !$newvalue);
137
  }
138
+
139
  /**
140
  * @return int Maximum number of alerts to show in dashboard widget.
141
  */
143
  return 5;
144
  }
145
 
146
+ // <editor-fold desc="Pruning Settings">
147
+
148
  /**
149
  * @return int The maximum number of alerts allowable.
150
  */
151
  public function GetMaxAllowedAlerts(){
152
  return 5000;
153
  }
154
+
155
  /**
156
  * @return string The default pruning date.
157
  */
158
  public function GetDefaultPruningDate(){
159
  return '1 month';
160
  }
161
+
162
  protected $_pruning = 0;
163
+
164
  /**
165
  * @return string The current pruning date.
166
  */
172
  }
173
  return $this->_pruning;
174
  }
175
+
176
  /**
177
  * @param string $newvalue The new pruning date.
178
  */
182
  $this->_pruning = $newvalue;
183
  }
184
  }
185
+
186
  /**
187
  * @return integer Maximum number of alerts to keep.
188
  */
190
  $val = (int)$this->_plugin->GetGlobalOption('pruning-limit');
191
  return $val ? $val : $this->GetMaxAllowedAlerts();
192
  }
193
+
194
  /**
195
  * @param integer $newvalue The new maximum number of alerts.
196
  */
198
  $newvalue = max(/*min(*/(int)$newvalue/*, $this->GetMaxAllowedAlerts())*/, 1);
199
  $this->_plugin->SetGlobalOption('pruning-limit', $newvalue);
200
  }
201
+
202
  public function SetPruningDateEnabled($enabled){
203
  $this->_plugin->SetGlobalOption('pruning-date-e', $enabled);
204
  }
205
+
206
  public function SetPruningLimitEnabled($enabled){
207
  $this->_plugin->SetGlobalOption('pruning-limit-e', $enabled);
208
  }
209
+
210
  public function IsPruningDateEnabled(){
211
  return $this->_plugin->GetGlobalOption('pruning-date-e', true);
212
  }
213
+
214
  public function IsPruningLimitEnabled(){
215
  return $this->_plugin->GetGlobalOption('pruning-limit-e', true);
216
  }
217
+
218
  public function IsRestrictAdmins(){
219
  return $this->_plugin->GetGlobalOption('restrict-admins', false);
220
  }
221
+
222
  public function SetRestrictAdmins($enable){
223
  $this->_plugin->SetGlobalOption('restrict-admins', (bool)$enable);
224
  }
225
 
226
+ // </editor-fold>
227
+
228
  protected $_disabled = null;
229
+
230
  public function GetDefaultDisabledAlerts(){
231
  return array(); //array(0000, 0003, 0005);
232
  }
233
+
234
  /**
235
  * @return array IDs of disabled alerts.
236
  */
243
  }
244
  return $this->_disabled;
245
  }
246
+
247
  /**
248
  * @param array $types IDs alerts to disable.
249
  */
251
  $this->_disabled = array_unique(array_map('intval', $types));
252
  $this->_plugin->SetGlobalOption('disabled-alerts', implode(',', $this->_disabled));
253
  }
254
+
255
+ public function IsIncognito(){
256
+ return $this->_plugin->GetGlobalOption('hide-plugin');
257
+ }
258
+
259
+ public function SetIncognito($enabled){
260
+ return $this->_plugin->SetGlobalOption('hide-plugin', $enabled);
261
+ }
262
 
263
+ // <editor-fold desc="Access Control">
264
 
265
+ protected $_viewers = null;
266
+
267
  public function SetAllowedPluginViewers($usersOrRoles){
268
  $this->_viewers = $usersOrRoles;
269
  $this->_plugin->SetGlobalOption('plugin-viewers', implode(',', $this->_viewers));
270
  }
271
+
272
  public function GetAllowedPluginViewers(){
273
  if(is_null($this->_viewers)){
274
  $this->_viewers = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-viewers'))));
275
  }
276
  return $this->_viewers;
277
  }
278
+
279
  protected $_editors = null;
280
+
281
  public function SetAllowedPluginEditors($usersOrRoles){
282
  $this->_editors = $usersOrRoles;
283
  $this->_plugin->SetGlobalOption('plugin-editors', implode(',', $this->_editors));
284
  }
285
+
286
  public function GetAllowedPluginEditors(){
287
  if(is_null($this->_editors)){
288
  $this->_editors = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-editors'))));
289
  }
290
  return $this->_editors;
291
  }
292
+
293
  protected $_perpage = null;
294
+
295
  public function SetViewPerPage($newvalue){
296
  $this->_perpage = max($newvalue, 1);
297
  $this->_plugin->SetGlobalOption('items-per-page', $this->_perpage);
298
  }
299
+
300
  public function GetViewPerPage(){
301
  if(is_null($this->_perpage)){
302
  $this->_perpage = (int)$this->_plugin->GetGlobalOption('items-per-page', 10);
303
  }
304
  return $this->_perpage;
305
  }
306
+
307
  /**
308
  * @param string $action Type of action, either 'view' or 'edit'.
309
  * @return boolean If user has access or not.
311
  public function CurrentUserCan($action){
312
  return $this->UserCan(wp_get_current_user(), $action);
313
  }
314
+
315
  /**
316
  * @return string[] List of superadmin usernames.
317
  */
318
  protected function GetSuperAdmins(){
319
  return $this->_plugin->IsMultisite() ? get_super_admins() : array();
320
  }
321
+
322
  /**
323
  * @return string[] List of admin usernames.
324
  */
326
  if($this->_plugin->IsMultisite()){
327
  // see: https://gist.github.com/1508426/65785a15b8638d43a9905effb59e4d97319ef8f8
328
  global $wpdb;
329
+ $cap = $wpdb->prefix."capabilities";
 
330
  $sql = "SELECT DISTINCT $wpdb->users.user_login"
331
  . " FROM $wpdb->users"
332
  . " INNER JOIN $wpdb->usermeta ON ($wpdb->users.ID = $wpdb->usermeta.user_id )"
340
  return $result;
341
  }
342
  }
343
+
344
  /**
345
  * Returns access tokens for a particular action.
346
  * @param string $action Type of action.
348
  */
349
  public function GetAccessTokens($action){
350
  $allowed = array();
351
+
352
  switch($action){
353
  case 'view':
354
  $allowed = $this->GetAllowedPluginViewers();
369
  default:
370
  throw new Exception('Unknown action "'.$action.'".');
371
  }
372
+
373
  if (!$this->IsRestrictAdmins()) {
374
  if(is_multisite()){
375
  $allowed = array_merge($allowed, get_super_admins());
377
  $allowed[] = 'administrator';
378
  }
379
  }
380
+
381
  return array_unique($allowed);
382
  }
383
+
384
  /**
385
  * @param integer|WP_user $user User object to check.
386
  * @param string $action Type of action, either 'view' or 'edit'.
388
  */
389
  public function UserCan($user, $action){
390
  if(is_int($user))$user = get_userdata($user);
391
+
392
  $allowed = $this->GetAccessTokens($action);
393
+
394
  $check = array_merge(
395
  $user->roles,
396
  array($user->user_login)
397
  );
398
+
399
  foreach($check as $item){
400
  if(in_array($item, $allowed)){
401
  return true;
402
  }
403
  }
 
404
  return false;
405
  }
406
+
407
  public function GetCurrentUserRoles($baseRoles = null){
408
  if ($baseRoles == null) $baseRoles = wp_get_current_user()->roles;
409
  if (function_exists('is_super_admin') && is_super_admin()) $baseRoles[] = 'superadmin';
410
  return $baseRoles;
411
  }
412
 
413
+ // </editor-fold>
 
 
 
 
 
 
414
 
415
+ // <editor-fold desc="Licensing">
416
+
417
  public function GetLicenses(){
418
  return $this->_plugin->GetGlobalOption('licenses');
419
  }
420
+
421
  public function GetLicense($name){
422
  $data = $this->GetLicenses();
423
  $name = sanitize_key(basename($name));
424
  return isset($data[$name]) ? $data[$name] : array();
425
  }
426
+
427
  public function SetLicenses($data){
428
  $this->_plugin->SetGlobalOption('licenses', $data);
429
  }
430
+
431
  public function GetLicenseKey($name){
432
  $data = $this->GetLicense($name);
433
  return isset($data['key']) ? $data['key'] : '';
434
  }
435
+
436
  public function GetLicenseStatus($name){
437
  $data = $this->GetLicense($name);
438
  return isset($data['sts']) ? $data['sts'] : '';
439
  }
440
+
441
  public function GetLicenseErrors($name){
442
  $data = $this->GetLicense($name);
443
  return isset($data['err']) ? $data['err'] : '';
444
  }
445
+
446
  public function SetLicenseKey($name, $key){
447
  $data = $this->GetLicenses();
448
  if (!isset($data[$name])) $data[$name] = array();
449
  $data[$name]['key'] = $key;
450
  $this->SetLicenses($data);
451
  }
452
+
453
  public function SetLicenseStatus($name, $status){
454
  $data = $this->GetLicenses();
455
  if (!isset($data[$name])) $data[$name] = array();
456
  $data[$name]['sts'] = $status;
457
  $this->SetLicenses($data);
458
  }
459
+
460
  public function SetLicenseErrors($name, $errors){
461
  $data = $this->GetLicenses();
462
  if (!isset($data[$name])) $data[$name] = array();
463
  $data[$name]['err'] = $errors;
464
  $this->SetLicenses($data);
465
  }
466
+
467
  public function ClearLicenses(){
468
  $this->SetLicenses(array());
469
  }
470
+
471
+ // </editor-fold>
472
+
473
+ // <editor-fold desc="Client IP Retrieval">
474
+
475
+ public function IsMainIPFromProxy(){
476
+ return $this->_plugin->GetGlobalOption('use-proxy-ip');
477
+ }
478
+
479
+ public function SetMainIPFromProxy($enabled){
480
+ return $this->_plugin->SetGlobalOption('use-proxy-ip', $enabled);
481
+ }
482
+
483
+ public function IsInternalIPsFiltered(){
484
+ return $this->_plugin->GetGlobalOption('filter-internal-ip');
485
+ }
486
+
487
+ public function SetInternalIPsFiltering($enabled){
488
+ return $this->_plugin->SetGlobalOption('filter-internal-ip', $enabled);
489
+ }
490
+
491
+ public function GetMainClientIP(){
492
+ $result = null;
493
+ if ($this->IsMainIPFromProxy()) {
494
+ // TODO the algorithm below just gets the first IP in the list...we might want to make this more intelligent somehow
495
+ $result = $this->GetClientIPs();
496
+ $result = reset($result);
497
+ $result = isset($result[0]) ? $result[0] : null;
498
+ }elseif(isset($_SERVER['REMOTE_ADDR'])){
499
+ $result = $this->NormalizeIP($_SERVER['REMOTE_ADDR']);
500
+ if (!$this->ValidateIP($result)) $result = null;
501
+ }
502
+ return $result;
503
+ }
504
+
505
+ public function GetClientIPs(){
506
+ $ips = array();
507
+ foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) {
508
+ if (isset($_SERVER[$key])) {
509
+ $ips[$key] = array();
510
+ foreach (explode(',', $_SERVER[$key]) as $ip)
511
+ if ($this->ValidateIP($ip = $this->NormalizeIP($ip)))
512
+ $ips[$key][] = $ip;
513
+ }
514
+ }
515
+ return $ips;
516
+ }
517
+
518
+ protected function NormalizeIP($ip){
519
+ $ip = trim($ip);
520
+ if(strpos($ip, ':') !== false && strpos($ip, '[') === false){
521
+ // IPv4 with a port (eg: 11.22.33.44:80)
522
+ $ip = explode(':', $ip);
523
+ $ip = $ip[0];
524
+ }else{
525
+ // IPv6 with a port (eg: [::1]:80)
526
+ $ip = explode(']', $ip);
527
+ $ip = ltrim($ip[0], '[');
528
+ }
529
+ return $ip;
530
+ }
531
+
532
+ protected function ValidateIP($ip){
533
+ $opts = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
534
+ if ($this->IsInternalIPsFiltered()) $opts = $opts | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;
535
+ return filter_var($ip, FILTER_VALIDATE_IP, $opts);
536
+ }
537
+
538
+ // </editor-fold>
539
  }
classes/Views/Extensions.php CHANGED
@@ -38,7 +38,7 @@ class WSAL_Views_Extensions extends WSAL_AbstractView {
38
  <h2><?php _e('Security Alerts Search Extension', 'wp-security-audit-log'); ?></h2>
39
  <strong><?php _e('Automatically Search for specific WordPress user and site activity in WordPress Security Audit Log.', 'wp-security-audit-log'); ?></strong>
40
  <p><?php _e('The Search Extension enables you to easily find specific WordPress activity in the Audit Log with free text based searches. Filters can also be used in conjunction with free text based searches to further narrow down and have more accurate search results.', 'wp-security-audit-log'); ?></p>
41
- <p><a class="button" href="http://www.wpwhitesecurity.com/plugins-premium-extensions/search-filtering-extension-wordpress/?utm_source=plugin&utm_medium=extensionspage&utm_campaign=search" target="_blank"><?php _e('More Information', 'wp-security-audit-log'); ?></a></p>
42
  </div>
43
 
44
  <div class="activity-block">
38
  <h2><?php _e('Security Alerts Search Extension', 'wp-security-audit-log'); ?></h2>
39
  <strong><?php _e('Automatically Search for specific WordPress user and site activity in WordPress Security Audit Log.', 'wp-security-audit-log'); ?></strong>
40
  <p><?php _e('The Search Extension enables you to easily find specific WordPress activity in the Audit Log with free text based searches. Filters can also be used in conjunction with free text based searches to further narrow down and have more accurate search results.', 'wp-security-audit-log'); ?></p>
41
+ <p><a class="button" href="http://www.wpwhitesecurity.com/plugins-premium-extensions/search-filtering-extension/?utm_source=plugin&utm_medium=extensionspage&utm_campaign=search" target="_blank"><?php _e('More Information', 'wp-security-audit-log'); ?></a></p>
42
  </div>
43
 
44
  <div class="activity-block">
classes/Views/Sandbox.php DELETED
@@ -1,286 +0,0 @@
1
- <?php
2
-
3
- class WSAL_Views_Sandbox extends WSAL_AbstractView {
4
-
5
- public function __construct(WpSecurityAuditLog $plugin) {
6
- parent::__construct($plugin);
7
- if(is_admin())add_action('wp_ajax_AjaxExecute', array($this, 'AjaxExecute'));
8
- }
9
-
10
- public function GetTitle() {
11
- return __('Sandbox', 'wp-security-audit-log');
12
- }
13
-
14
- public function GetIcon() {
15
- return 'dashicons-admin-generic';
16
- }
17
-
18
- public function GetName() {
19
- return __('Sandbox', 'wp-security-audit-log');
20
- }
21
-
22
- public function GetWeight() {
23
- return 5;
24
- }
25
-
26
- public function IsAccessible(){
27
- return $this->_plugin->settings->CurrentUserCan('edit')
28
- && $this->_plugin->settings->IsSandboxPageEnabled();
29
- }
30
-
31
- protected $exec_data = array();
32
- protected $exec_info = array();
33
-
34
- protected $snippets = array(
35
- '' => '',
36
- 'Current WP User' => 'return wp_get_current_user();',
37
-
38
- 'Clean PHP Error Events' => '
39
- class OccurrenceCleanupTask extends WSAL_AbstractSandboxTask {
40
-
41
- protected $event_ids = array(0000, 0001, 0002, 0003, 0004, 0005);
42
-
43
- protected function Execute(){
44
- global $wpdb;
45
- $occs = WSAL_DB_Occurrence::LoadMulti(\'alert_id IN (\'.implode(\',\', $this->event_ids).\')\');
46
- $c = count($occs);
47
- $this->Message($c ? (\'Removing \' . $c . \' events...\') : \'No events to remove!\');
48
- foreach($occs as $i => $occ){
49
- $this->Message(\'Removing Event \' . $occ->id . \'...\', true);
50
- $occ->Delete();
51
- $this->Progress(($i + 1) / $c * 100);
52
- }
53
- }
54
- }
55
- new OccurrenceCleanupTask();',
56
-
57
- 'Multisite Site Creator' => '
58
- class DummySiteCreatorTask extends WSAL_AbstractSandboxTask {
59
-
60
- protected $sites_to_create = 100;
61
- protected $site_host = \'localhost\';
62
- protected $site_path = \'/wordpress-3.8/test$i/\';
63
- protected $site_name = \'Test $i\';
64
-
65
- protected function Execute(){
66
- global $wpdb;
67
- $l = $wpdb->get_var("SELECT blog_id FROM $wpdb->blogs ORDER BY blog_id DESC LIMIT 1") + 1;
68
- $this->Message(\'Creating \' . $this->sites_to_create . \' new sites...\');
69
- for($i = $l; $i <= $this->sites_to_create + $l; $i++){
70
- $this->Progress(($i - $l) / $this->sites_to_create * 100);
71
- wpmu_create_blog(
72
- str_replace(\'$i\', $i, $this->site_host),
73
- str_replace(\'$i\', $i, $this->site_path),
74
- str_replace(\'$i\', $i, $this->site_name),
75
- 1);
76
- }
77
- }
78
- }
79
- new DummySiteCreatorTask();',
80
- 'Get Access Tokens' => '$settings = WpSecurityAuditLog::GetInstance()->settings;
81
- return array(
82
- \'view\' => $settings->GetAccessTokens(\'view\'),
83
- \'edit\' => $settings->GetAccessTokens(\'edit\'),
84
- );',
85
- 'Show Profiler Results' => 'return array_map(\'strval\', WpSecurityAuditLog::GetInstance()->profiler->GetItems());',
86
- 'Reset Notices' => 'foreach (WSAL_AbstractView::$AllowedNoticeNames as $name) delete_user_meta(get_current_user_id(), "wsal-notice-$name");',
87
- );
88
-
89
- public function HandleError($code, $message, $filename = 'unknown', $lineno = 0){
90
- if(!isset($this->exec_data['Errors']))
91
- $this->exec_data['Errors'] = array();
92
- $this->exec_data['Errors'] = new ErrorException($message, $code, 0, $filename, $lineno);
93
- return true;
94
- }
95
-
96
- protected function BeforeExecute(){
97
- $this->exec_info['_Time'] = microtime(true);
98
- $this->exec_info['_Mem'] = memory_get_usage();
99
- }
100
-
101
- protected function AfterExecute(){
102
- $this->exec_info['Time'] = microtime(true) - $this->exec_info['_Time'];
103
- $this->exec_info['Mem'] = memory_get_usage() - $this->exec_info['_Mem'];
104
- if($this->exec_info['Time'] < 0.001){
105
- $this->exec_info['Time'] = number_format($this->exec_info['Time'] * 1000, 3) . 'ms';
106
- }else{
107
- $this->exec_info['Time'] = number_format($this->exec_info['Time'], 3) . 's';
108
- }
109
- $this->exec_info['Mem'] = size_format($this->exec_info['Mem']);
110
- $this->exec_info['Queries'] = get_num_queries();
111
- }
112
-
113
- protected function Execute($code){
114
- try {
115
- error_reporting(-1);
116
- ini_set('display_errors', false);
117
- if(function_exists('xdebug_disable'))xdebug_disable();
118
-
119
- set_error_handler(array($this, 'HandleError'));
120
-
121
- ob_start();
122
-
123
- $this->BeforeExecute();
124
- $this->exec_data['Result'] = eval($code);
125
- $this->AfterExecute();
126
-
127
- $this->exec_data['Output'] = ob_get_clean();
128
-
129
- if(!$this->exec_data['Output'])
130
- unset($this->exec_data['Output']);
131
-
132
- restore_error_handler();
133
- } catch (Exception $ex) {
134
- if(!isset($this->exec_data['Errors']))
135
- $this->exec_data['Errors'] = array();
136
- $this->exec_data['Errors'][] = $ex;
137
- }
138
- }
139
-
140
- public function AjaxExecuteResponse(){
141
- echo '<!DOCTYPE html><html><head>';
142
- echo '<link rel="stylesheet" id="open-sans-css" href="' . $this->_plugin->GetBaseUrl() . '/css/nice_r.css" type="text/css" media="all"/>';
143
- echo '<script type="text/javascript" src="'.$this->_plugin->GetBaseUrl() . '/js/nice_r.js"></script>';
144
- echo '<style type="text/css">';
145
- echo 'html, body { margin: 0; padding: 0; }';
146
- echo '.nice_r { position: absolute; padding: 8px; }';
147
- echo '.nice_r a { overflow: visible; }';
148
- echo '.faerror { font: 14px Arial; background: #FCC; text-align: center; padding: 32px; }';
149
- echo '</style>';
150
- echo '</head><body>';
151
-
152
- if(($e = error_get_last()) && (!isset($this->exec_data['Errors']) || !count($this->exec_data['Errors'])))
153
- $this->HandleError($e['type'], $e['message'], $e['file'], $e['line']);
154
-
155
- if(count($this->exec_data)){
156
- $result = new WSAL_Nicer($this->exec_data, true);
157
- $result->render();
158
- }else echo '<div class="faerror">FATAL ERROR</div>';
159
-
160
- if(count($this->exec_info)){
161
- ?><script type="text/javascript">
162
- window.parent.SandboxUpdateState(<?php
163
- $res = array();
164
- foreach($this->exec_info as $key => $val)
165
- if($key && $key[0] != '_')
166
- $res[$key] = $val;
167
- echo json_encode($res);
168
- ?>);
169
- </script><?php
170
- }
171
-
172
- echo '</body></html>';
173
- }
174
-
175
- public function AjaxExecute(){
176
- if(!$this->_plugin->settings->IsSandboxPageEnabled())
177
- die('Sandbox Disabled.');
178
- if(!$this->_plugin->settings->CurrentUserCan('edit'))
179
- die('Access Denied.');
180
- if(!isset($_REQUEST['code']))
181
- die('Code parameter expected.');
182
-
183
- register_shutdown_function(array($this, 'AjaxExecuteResponse'));
184
- $this->Execute(stripslashes_deep($_REQUEST['code']));
185
- die;
186
- }
187
-
188
- public function Render(){
189
- $snpt = isset($_REQUEST['snippet']) ? $_REQUEST['snippet'] : '';
190
- $code = isset($this->snippets[$snpt]) ? $this->snippets[$snpt] : '';
191
- ?><form id="sandbox" method="post" target="execframe" action="<?php echo admin_url('admin-ajax.php'); ?>">
192
- <input type="hidden" name="action" value="AjaxExecute" />
193
- <div id="sandbox-wrap-wrap">
194
- <div id="sandbox-wrap">
195
- <textarea name="code" id="sandbox-code"><?php echo esc_html($code); ?></textarea>
196
- <iframe id="sandbox-result" name="execframe"></iframe>
197
- </div>
198
- <div id="sandbox-status"><?php _e('Ready.', 'wp-security-audit-log'); ?></div>
199
- </div>
200
- <label for="sandbox-snippet" style="float: left; line-height: 26px; display: inline-block; margin-right: 32px; border-right: 1px dotted #CCC; padding-right: 32px;">
201
- Use Snippet:
202
- <select id="sandbox-snippet" onchange="SandboxUseSnippet(this.value);"><?php
203
- foreach(array_keys($this->snippets) as $name){
204
- ?><option value="<?php echo esc_attr($name); ?>"<?php if($name == $snpt)echo ' selected="selected"'; ?>><?php echo $name; ?></option><?php
205
- }
206
- ?></select>
207
- </label>
208
- <input type="submit" name="submit" id="sandbox-submit" class="button button-primary" value="Execute">
209
- <img id="sandbox-loader" style="margin: 6px 12px; display: none;" src="http://cdnjs.cloudflare.com/ajax/libs/jstree/3.0.0-beta10/themes/default/throbber.gif" width="16" height="16" alt="Loading..."/>
210
- </form><?php
211
- }
212
-
213
- public function Header(){
214
- ?><link rel="stylesheet" href="//cdn.jsdelivr.net/codemirror/4.0.3/codemirror.css">
215
- <style type="text/css">
216
- #sandbox-wrap-wrap {
217
- resize: vertical; height: 400px; overflow: auto; margin: 16px 0; padding-bottom: 16px; position: relative; border: 1px solid #DDD;
218
- }
219
- #sandbox-wrap {
220
- overflow: hidden; height: 100% !important; position: relative; box-sizing: border-box;
221
- }
222
- #sandbox-wrap textarea,
223
- #sandbox-wrap .CodeMirror {
224
- resize: none; width: 50%; height: 100%; border-bottom: 1px solid #ddd; font: 12px Consolas; box-sizing: border-box;
225
- }
226
- #sandbox-wrap iframe {
227
- resize: none; width: 50%; height: 100%; border-bottom: 1px solid #ddd; background: #FFF; position: absolute; top: 0; right: 0; box-sizing: border-box; border-left: 4px solid #DDD;
228
- }
229
- #sandbox-status {
230
- font: 10px Tahoma; padding: 2px; position: absolute; left: 0; right: 16px; bottom: 0;
231
- }
232
- #sandbox-status ul {
233
- list-style: none; margin: 0;
234
- }
235
- #sandbox-status li {
236
- float: left; padding-right: 4px; border-right: 1px solid #CCC; margin: 0 4px 0 0;
237
- }
238
- </style><?php
239
- }
240
-
241
- public function Footer(){
242
- ?><script src="//cdn.jsdelivr.net/codemirror/4.0.3/codemirror.js"></script>
243
- <script src="//cdn.jsdelivr.net/codemirror/4.0.3/addon/edit/matchbrackets.js"></script>
244
- <script src="//cdn.jsdelivr.net/codemirror/4.0.3/mode/clike/clike.js"></script>
245
- <script src="//cdn.jsdelivr.net/codemirror/4.0.3/mode/php/php.js"></script>
246
- <script type="text/javascript">
247
- jQuery(document).ready(function(){
248
- var ed = CodeMirror.fromTextArea(
249
- jQuery('#sandbox-code')[0],
250
- {
251
- lineNumbers: true,
252
- matchBrackets: true,
253
- mode: "text/x-php",
254
- indentUnit: 4,
255
- indentWithTabs: true
256
- }
257
- );
258
-
259
- jQuery('#sandbox').submit(function(){
260
- if(!ed.isClean())jQuery('#sandbox-snippet').val('');
261
- jQuery('#sandbox-loader').show();
262
- });
263
-
264
- jQuery('#sandbox-result').on('load error', function(){
265
- jQuery('#sandbox-loader').hide();
266
- });
267
-
268
- //jQuery('#sandbox').submit();
269
- });
270
-
271
- function SandboxUseSnippet(value){
272
- jQuery('#sandbox-submit').attr('disabled', true);
273
- location = <?php echo json_encode(admin_url('admin.php?page=wsal-sandbox')); ?>
274
- + '&snippet=' + encodeURIComponent(value);
275
- }
276
-
277
- function SandboxUpdateState(data){
278
- var ul = jQuery('<ul/>');
279
- for(var key in data)
280
- ul.append(jQuery('<li/>').text(key + ': ' + data[key]));
281
- jQuery('#sandbox-status').html('').append(ul);
282
- }
283
- </script><?php
284
- }
285
-
286
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/Views/Settings.php CHANGED
@@ -52,6 +52,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
52
  $this->_plugin->settings->SetAllowedPluginEditors(isset($_REQUEST['Editors']) ? $_REQUEST['Editors'] : array());
53
  $this->_plugin->settings->SetRestrictAdmins(isset($_REQUEST['RestrictAdmins']));
54
  $this->_plugin->settings->SetRefreshAlertsEnabled($_REQUEST['EnableAuditViewRefresh']);
 
 
55
  $this->_plugin->settings->SetIncognito(isset($_REQUEST['Incognito']));
56
  $this->_plugin->settings->ClearDevOptions();
57
  if(isset($_REQUEST['DevOptions']))
@@ -177,6 +179,26 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
177
  </fieldset>
178
  </td>
179
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  <tr>
181
  <th><label for="ViewerQueryBox"><?php _e('Can View Alerts', 'wp-security-audit-log'); ?></label></th>
182
  <td>
@@ -280,10 +302,6 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
280
  __('Request Log', 'wp-security-audit-log'),
281
  __('Enables logging request to file.', 'wp-security-audit-log')
282
  ),
283
- WSAL_Settings::OPT_DEV_SANDBOX_PAGE => array(
284
- __('Sandbox', 'wp-security-audit-log'),
285
- __('Enables sandbox for testing PHP code.', 'wp-security-audit-log')
286
- ),
287
  WSAL_Settings::OPT_DEV_BACKTRACE_LOG => array(
288
  __('Backtrace', 'wp-security-audit-log'),
289
  __('Log full backtrace for PHP-generated alerts.', 'wp-security-audit-log')
52
  $this->_plugin->settings->SetAllowedPluginEditors(isset($_REQUEST['Editors']) ? $_REQUEST['Editors'] : array());
53
  $this->_plugin->settings->SetRestrictAdmins(isset($_REQUEST['RestrictAdmins']));
54
  $this->_plugin->settings->SetRefreshAlertsEnabled($_REQUEST['EnableAuditViewRefresh']);
55
+ $this->_plugin->settings->SetMainIPFromProxy($_REQUEST['EnableProxyIpCapture']);
56
+ $this->_plugin->settings->SetInternalIPsFiltering($_REQUEST['EnableIpFiltering']);
57
  $this->_plugin->settings->SetIncognito(isset($_REQUEST['Incognito']));
58
  $this->_plugin->settings->ClearDevOptions();
59
  if(isset($_REQUEST['DevOptions']))
179
  </fieldset>
180
  </td>
181
  </tr>
182
+ <tr>
183
+ <th><label for="pioption_on"><?php _e('Reverse Proxy / Firewall Options', 'wp-security-audit-log'); ?></label></th>
184
+ <td>
185
+ <fieldset>
186
+ <label for="EnableProxyIpCapture">
187
+ <input type="checkbox" name="EnableProxyIpCapture" value="1" id="EnableProxyIpCapture"<?php
188
+ if($this->_plugin->settings->IsMainIPFromProxy())echo ' checked="checked"';
189
+ ?>/> <?php _e('WordPress running behind firewall or proxy', 'wp-security-audit-log'); ?><br/>
190
+ <span class="description"><?php _e('Enable this option if your WordPress is running behind a firewall or reverse proxy. When this option is enabled the plugin will retrieve the user\'s IP address from the proxy header.', 'wp-security-audit-log'); ?></span>
191
+ </label>
192
+ <br/>
193
+ <label for="EnableIpFiltering">
194
+ <input type="checkbox" name="EnableIpFiltering" value="1" id="EnableIpFiltering"<?php
195
+ if($this->_plugin->settings->IsInternalIPsFiltered())echo ' checked="checked"';
196
+ ?>/> <?php _e('Filter Internal IP Addresses', 'wp-security-audit-log'); ?><br/>
197
+ <span class="description"><?php _e('Enable this option to filter internal IP addresses from the proxy headers.', 'wp-security-audit-log'); ?></span>
198
+ </label>
199
+ </fieldset>
200
+ </td>
201
+ </tr>
202
  <tr>
203
  <th><label for="ViewerQueryBox"><?php _e('Can View Alerts', 'wp-security-audit-log'); ?></label></th>
204
  <td>
302
  __('Request Log', 'wp-security-audit-log'),
303
  __('Enables logging request to file.', 'wp-security-audit-log')
304
  ),
 
 
 
 
305
  WSAL_Settings::OPT_DEV_BACKTRACE_LOG => array(
306
  __('Backtrace', 'wp-security-audit-log'),
307
  __('Log full backtrace for PHP-generated alerts.', 'wp-security-audit-log')
languages/wp-security-audit-log.pot CHANGED
@@ -2,9 +2,9 @@
2
  # This file is distributed under the same license as the WP Security Audit Log package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WP Security Audit Log 1.3.1\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-security-audit-log\n"
7
- "POT-Creation-Date: 2014-11-27 13:07:22+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
@@ -76,7 +76,7 @@ msgstr ""
76
  msgid "System"
77
  msgstr ""
78
 
79
- #: classes/AuditLogListView.php:195
80
  msgid "Alert Data Inspector"
81
  msgstr ""
82
 
@@ -221,7 +221,7 @@ msgid "Audit Log Viewer"
221
  msgstr ""
222
 
223
  #: classes/Views/AuditLog.php:64 classes/Views/Licensing.php:34
224
- #: classes/Views/Settings.php:80 classes/Views/ToggleAlerts.php:29
225
  msgid "You do not have sufficient permissions to access this page."
226
  msgstr ""
227
 
@@ -419,12 +419,12 @@ msgstr ""
419
  msgid "Licensing"
420
  msgstr ""
421
 
422
- #: classes/Views/Licensing.php:39 classes/Views/Settings.php:85
423
  #: classes/Views/ToggleAlerts.php:44
424
  msgid "Settings have been saved."
425
  msgstr ""
426
 
427
- #: classes/Views/Licensing.php:41 classes/Views/Settings.php:87
428
  #: classes/Views/ToggleAlerts.php:46
429
  msgid "Error: "
430
  msgstr ""
@@ -441,96 +441,111 @@ msgstr ""
441
  msgid "Inactive"
442
  msgstr ""
443
 
444
- #: classes/Views/Sandbox.php:11 classes/Views/Sandbox.php:19
445
- #: classes/Views/Settings.php:284
446
- msgid "Sandbox"
447
- msgstr ""
448
-
449
- #: classes/Views/Sandbox.php:198
450
- msgid "Ready."
451
- msgstr ""
452
-
453
  #: classes/Views/Settings.php:18 classes/Views/Settings.php:26
454
  msgid "Settings"
455
  msgstr ""
456
 
457
- #: classes/Views/Settings.php:110
458
  msgid "Security Alerts Pruning"
459
  msgstr ""
460
 
461
- #: classes/Views/Settings.php:113 classes/Views/Settings.php:121
462
  msgid "(eg: 1 month)"
463
  msgstr ""
464
 
465
- #: classes/Views/Settings.php:117
466
  msgid "None"
467
  msgstr ""
468
 
469
- #: classes/Views/Settings.php:125
470
  msgid "Delete alerts older than"
471
  msgstr ""
472
 
473
- #: classes/Views/Settings.php:133
474
  msgid "(eg: 80)"
475
  msgstr ""
476
 
477
- #: classes/Views/Settings.php:137
478
  msgid "Keep up to"
479
  msgstr ""
480
 
481
- #: classes/Views/Settings.php:142
482
  msgid "alerts"
483
  msgstr ""
484
 
485
- #: classes/Views/Settings.php:146
486
  msgid "Next Scheduled Cleanup is in "
487
  msgstr ""
488
 
489
- #: classes/Views/Settings.php:150
490
  msgid "(or %s)"
491
  msgstr ""
492
 
493
- #: classes/Views/Settings.php:151
494
  msgid "Run Manually"
495
  msgstr ""
496
 
497
- #: classes/Views/Settings.php:157
498
  msgid "Alerts Dashboard Widget"
499
  msgstr ""
500
 
501
- #: classes/Views/Settings.php:163
502
  msgid "On"
503
  msgstr ""
504
 
505
- #: classes/Views/Settings.php:168
506
  msgid "Off"
507
  msgstr ""
508
 
509
- #: classes/Views/Settings.php:173
510
  msgid "Display a dashboard widget with the latest %d security alerts."
511
  msgstr ""
512
 
513
- #: classes/Views/Settings.php:181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
514
  msgid "Can View Alerts"
515
  msgstr ""
516
 
517
- #: classes/Views/Settings.php:188
518
  msgid "Users and Roles in this list can view the security alerts"
519
  msgstr ""
520
 
521
- #: classes/Views/Settings.php:203
522
  msgid "Can Manage Plugin"
523
  msgstr ""
524
 
525
- #: classes/Views/Settings.php:210
526
  msgid "Users and Roles in this list can manage the plugin settings"
527
  msgstr ""
528
 
529
- #: classes/Views/Settings.php:225
530
  msgid "Restrict Plugin Access"
531
  msgstr ""
532
 
533
- #: classes/Views/Settings.php:233
534
  msgid ""
535
  "By default all the administrators on this WordPress have access to manage "
536
  "this plugin.<br/>By enabling this option only the users specified in the two "
@@ -538,78 +553,74 @@ msgid ""
538
  "this plugin."
539
  msgstr ""
540
 
541
- #: classes/Views/Settings.php:240
542
  msgid "Refresh Audit View"
543
  msgstr ""
544
 
545
- #: classes/Views/Settings.php:246
546
  msgid "Automatic"
547
  msgstr ""
548
 
549
- #: classes/Views/Settings.php:248
550
  msgid "Refresh Audit View as soon as there are new events."
551
  msgstr ""
552
 
553
- #: classes/Views/Settings.php:252
554
  msgid "Manual"
555
  msgstr ""
556
 
557
- #: classes/Views/Settings.php:254
558
  msgid "Refresh Audit View only when page is reloaded."
559
  msgstr ""
560
 
561
- #: classes/Views/Settings.php:260
562
  msgid "Developer Options"
563
  msgstr ""
564
 
565
- #: classes/Views/Settings.php:268
566
  msgid ""
567
  "Only enable these options on testing, staging and development websites. "
568
  "Enabling any of the settings below on LIVE websites may cause unintended "
569
  "side-effects including degraded performance."
570
  msgstr ""
571
 
572
- #: classes/Views/Settings.php:272
573
  msgid "Data Inspector"
574
  msgstr ""
575
 
576
- #: classes/Views/Settings.php:273
577
  msgid "View data logged for each triggered alert."
578
  msgstr ""
579
 
580
- #: classes/Views/Settings.php:276
581
  msgid "PHP Errors"
582
  msgstr ""
583
 
584
- #: classes/Views/Settings.php:277
585
  msgid "Enables sensor for alerts generated from PHP."
586
  msgstr ""
587
 
588
- #: classes/Views/Settings.php:280
589
  msgid "Request Log"
590
  msgstr ""
591
 
592
- #: classes/Views/Settings.php:281
593
  msgid "Enables logging request to file."
594
  msgstr ""
595
 
596
- #: classes/Views/Settings.php:285
597
- msgid "Enables sandbox for testing PHP code."
598
- msgstr ""
599
-
600
- #: classes/Views/Settings.php:288
601
  msgid "Backtrace"
602
  msgstr ""
603
 
604
- #: classes/Views/Settings.php:289
605
  msgid "Log full backtrace for PHP-generated alerts."
606
  msgstr ""
607
 
608
- #: classes/Views/Settings.php:307
609
  msgid "Hide Plugin from Plugins Page"
610
  msgstr ""
611
 
612
- #: classes/Views/Settings.php:313
613
  msgid "Hide"
614
  msgstr ""
615
 
2
  # This file is distributed under the same license as the WP Security Audit Log package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WP Security Audit Log 1.3.2\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-security-audit-log\n"
7
+ "POT-Creation-Date: 2014-12-16 10:47:47+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
76
  msgid "System"
77
  msgstr ""
78
 
79
+ #: classes/AuditLogListView.php:205
80
  msgid "Alert Data Inspector"
81
  msgstr ""
82
 
221
  msgstr ""
222
 
223
  #: classes/Views/AuditLog.php:64 classes/Views/Licensing.php:34
224
+ #: classes/Views/Settings.php:82 classes/Views/ToggleAlerts.php:29
225
  msgid "You do not have sufficient permissions to access this page."
226
  msgstr ""
227
 
419
  msgid "Licensing"
420
  msgstr ""
421
 
422
+ #: classes/Views/Licensing.php:39 classes/Views/Settings.php:87
423
  #: classes/Views/ToggleAlerts.php:44
424
  msgid "Settings have been saved."
425
  msgstr ""
426
 
427
+ #: classes/Views/Licensing.php:41 classes/Views/Settings.php:89
428
  #: classes/Views/ToggleAlerts.php:46
429
  msgid "Error: "
430
  msgstr ""
441
  msgid "Inactive"
442
  msgstr ""
443
 
 
 
 
 
 
 
 
 
 
444
  #: classes/Views/Settings.php:18 classes/Views/Settings.php:26
445
  msgid "Settings"
446
  msgstr ""
447
 
448
+ #: classes/Views/Settings.php:112
449
  msgid "Security Alerts Pruning"
450
  msgstr ""
451
 
452
+ #: classes/Views/Settings.php:115 classes/Views/Settings.php:123
453
  msgid "(eg: 1 month)"
454
  msgstr ""
455
 
456
+ #: classes/Views/Settings.php:119
457
  msgid "None"
458
  msgstr ""
459
 
460
+ #: classes/Views/Settings.php:127
461
  msgid "Delete alerts older than"
462
  msgstr ""
463
 
464
+ #: classes/Views/Settings.php:135
465
  msgid "(eg: 80)"
466
  msgstr ""
467
 
468
+ #: classes/Views/Settings.php:139
469
  msgid "Keep up to"
470
  msgstr ""
471
 
472
+ #: classes/Views/Settings.php:144
473
  msgid "alerts"
474
  msgstr ""
475
 
476
+ #: classes/Views/Settings.php:148
477
  msgid "Next Scheduled Cleanup is in "
478
  msgstr ""
479
 
480
+ #: classes/Views/Settings.php:152
481
  msgid "(or %s)"
482
  msgstr ""
483
 
484
+ #: classes/Views/Settings.php:153
485
  msgid "Run Manually"
486
  msgstr ""
487
 
488
+ #: classes/Views/Settings.php:159
489
  msgid "Alerts Dashboard Widget"
490
  msgstr ""
491
 
492
+ #: classes/Views/Settings.php:165
493
  msgid "On"
494
  msgstr ""
495
 
496
+ #: classes/Views/Settings.php:170
497
  msgid "Off"
498
  msgstr ""
499
 
500
+ #: classes/Views/Settings.php:175
501
  msgid "Display a dashboard widget with the latest %d security alerts."
502
  msgstr ""
503
 
504
+ #: classes/Views/Settings.php:183
505
+ msgid "Reverse Proxy / Firewall Options"
506
+ msgstr ""
507
+
508
+ #: classes/Views/Settings.php:189
509
+ msgid "WordPress running behind firewall or proxy"
510
+ msgstr ""
511
+
512
+ #: classes/Views/Settings.php:190
513
+ msgid ""
514
+ "Enable this option if your WordPress is running behind a firewall or reverse "
515
+ "proxy. When this option is enabled the plugin will retrieve the user's IP "
516
+ "address from the proxy header."
517
+ msgstr ""
518
+
519
+ #: classes/Views/Settings.php:196
520
+ msgid "Filter Internal IP Addresses"
521
+ msgstr ""
522
+
523
+ #: classes/Views/Settings.php:197
524
+ msgid ""
525
+ "Enable this option to filter internal IP addresses from the proxy headers."
526
+ msgstr ""
527
+
528
+ #: classes/Views/Settings.php:203
529
  msgid "Can View Alerts"
530
  msgstr ""
531
 
532
+ #: classes/Views/Settings.php:210
533
  msgid "Users and Roles in this list can view the security alerts"
534
  msgstr ""
535
 
536
+ #: classes/Views/Settings.php:225
537
  msgid "Can Manage Plugin"
538
  msgstr ""
539
 
540
+ #: classes/Views/Settings.php:232
541
  msgid "Users and Roles in this list can manage the plugin settings"
542
  msgstr ""
543
 
544
+ #: classes/Views/Settings.php:247
545
  msgid "Restrict Plugin Access"
546
  msgstr ""
547
 
548
+ #: classes/Views/Settings.php:255
549
  msgid ""
550
  "By default all the administrators on this WordPress have access to manage "
551
  "this plugin.<br/>By enabling this option only the users specified in the two "
553
  "this plugin."
554
  msgstr ""
555
 
556
+ #: classes/Views/Settings.php:262
557
  msgid "Refresh Audit View"
558
  msgstr ""
559
 
560
+ #: classes/Views/Settings.php:268
561
  msgid "Automatic"
562
  msgstr ""
563
 
564
+ #: classes/Views/Settings.php:270
565
  msgid "Refresh Audit View as soon as there are new events."
566
  msgstr ""
567
 
568
+ #: classes/Views/Settings.php:274
569
  msgid "Manual"
570
  msgstr ""
571
 
572
+ #: classes/Views/Settings.php:276
573
  msgid "Refresh Audit View only when page is reloaded."
574
  msgstr ""
575
 
576
+ #: classes/Views/Settings.php:282
577
  msgid "Developer Options"
578
  msgstr ""
579
 
580
+ #: classes/Views/Settings.php:290
581
  msgid ""
582
  "Only enable these options on testing, staging and development websites. "
583
  "Enabling any of the settings below on LIVE websites may cause unintended "
584
  "side-effects including degraded performance."
585
  msgstr ""
586
 
587
+ #: classes/Views/Settings.php:294
588
  msgid "Data Inspector"
589
  msgstr ""
590
 
591
+ #: classes/Views/Settings.php:295
592
  msgid "View data logged for each triggered alert."
593
  msgstr ""
594
 
595
+ #: classes/Views/Settings.php:298
596
  msgid "PHP Errors"
597
  msgstr ""
598
 
599
+ #: classes/Views/Settings.php:299
600
  msgid "Enables sensor for alerts generated from PHP."
601
  msgstr ""
602
 
603
+ #: classes/Views/Settings.php:302
604
  msgid "Request Log"
605
  msgstr ""
606
 
607
+ #: classes/Views/Settings.php:303
608
  msgid "Enables logging request to file."
609
  msgstr ""
610
 
611
+ #: classes/Views/Settings.php:306
 
 
 
 
612
  msgid "Backtrace"
613
  msgstr ""
614
 
615
+ #: classes/Views/Settings.php:307
616
  msgid "Log full backtrace for PHP-generated alerts."
617
  msgstr ""
618
 
619
+ #: classes/Views/Settings.php:325
620
  msgid "Hide Plugin from Plugins Page"
621
  msgstr ""
622
 
623
+ #: classes/Views/Settings.php:331
624
  msgid "Hide"
625
  msgstr ""
626
 
readme.txt CHANGED
@@ -6,8 +6,8 @@ License: GPLv3
6
  License URI: http://www.gnu.org/licenses/gpl.html
7
  Tags: wordpress security plugin, wordpress security audit log, audit log, wordpress log, event log wordpress, wordpress user tracking, wordpress activity log, wordpress audit, security event log, audit trail, security audit trail, wordpress security alerts, wordpress monitor, wordpress security monitor, wordpress admin, wordpress admin monitoring, analytics, activity, admin, multisite, wordpress multisite, actions, dashboard, log, notification, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report
8
  Requires at least: 3.6
9
- Tested up to: 4.0.1
10
- Stable tag: 1.3.1
11
 
12
  Identify WordPress issues before they become a security problem by keeping an audit log of users and all of the under the hood WordPress activity.
13
 
@@ -93,6 +93,7 @@ NOTE: Developer options should NEVER be enabled on Live websites. They should on
93
  WP Security Audit Log plugin also has a number of features that make WordPress and WordPress multisite monitoring and auditing easier, such as:
94
 
95
  * Realtime Audit Log viewer to watch user activity as it happens without any delays
 
96
  * Limit who can view the security alerts by users or roles
97
  * Limit who can manage the plugin by users or roles
98
  * Configurable WordPress dashboard widget highlighting the most recent critical activity
@@ -109,15 +110,16 @@ WP Security Audit Log plugin also has a number of features that make WordPress a
109
  * [Design Wall](http://www.designwall.com/blog/10-wordpress-multisite-plugins-you-shouldnt-live-without/)
110
  * [WPLift](http://wplift.com/wordpress-event-tracking)
111
 
112
- = WordPress Security Tips & Tricks =
113
- Even if WordPress security is not your cup of tea, the security of your WordPress is your responsibility. Keep yourself up to date with the latest WordPress Security Tips & Tricks. WP White Security frequently publishes WordPress security tips & tricks on the [WordPress Security section](http://www.wpwhitesecurity.com/wordpress-security/) of their blog.
114
-
115
- = Further Reading =
116
  For more information and to get started with WordPress Security, check out the following:
117
 
 
 
 
118
  * [Official WP Security Audit Log Page](http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/)
119
- * [List of all WP Security Audit Log Alerts](http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/security-audit-alerts-logs/)
120
- * [Recipe for ultimate WordPress Security](http://www.wpwhitesecurity.com/wordpress-security/recipe-ultimate-diy-wordpress-security/)
 
121
 
122
  = Plugin Newsletter =
123
  To keep yourself updated with what is new and updated in our WordPress security plugins please subscribe to the [WP White Security Plugins Newsletter](http://eepurl.com/Jn9sP).
@@ -162,6 +164,19 @@ Yes it is possible to do so with the premium [WSAL Reporting Extension](http://w
162
 
163
  == Changelog ==
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  = 1.3.1 (2014-11-27) =
166
  * **New WordPress Security Alerts**
167
  * Alert 2065: The content of published post has been modified
6
  License URI: http://www.gnu.org/licenses/gpl.html
7
  Tags: wordpress security plugin, wordpress security audit log, audit log, wordpress log, event log wordpress, wordpress user tracking, wordpress activity log, wordpress audit, security event log, audit trail, security audit trail, wordpress security alerts, wordpress monitor, wordpress security monitor, wordpress admin, wordpress admin monitoring, analytics, activity, admin, multisite, wordpress multisite, actions, dashboard, log, notification, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report
8
  Requires at least: 3.6
9
+ Tested up to: 4.1
10
+ Stable tag: 1.3.2
11
 
12
  Identify WordPress issues before they become a security problem by keeping an audit log of users and all of the under the hood WordPress activity.
13
 
93
  WP Security Audit Log plugin also has a number of features that make WordPress and WordPress multisite monitoring and auditing easier, such as:
94
 
95
  * Realtime Audit Log viewer to watch user activity as it happens without any delays
96
+ * Builtin support for reverse proxies and web application firewalls [more information](http://www.wpwhitesecurity.com/wordpress-plugins/wordpress-user-monitoring-plugin/wp-security-audit-log-plugin-retrieves-originating-wordpress-user-ip-address/)
97
  * Limit who can view the security alerts by users or roles
98
  * Limit who can manage the plugin by users or roles
99
  * Configurable WordPress dashboard widget highlighting the most recent critical activity
110
  * [Design Wall](http://www.designwall.com/blog/10-wordpress-multisite-plugins-you-shouldnt-live-without/)
111
  * [WPLift](http://wplift.com/wordpress-event-tracking)
112
 
113
+ = Related Links and Documentation =
 
 
 
114
  For more information and to get started with WordPress Security, check out the following:
115
 
116
+ * [List of WordPress Security Alerts](http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/security-audit-alerts-logs/)
117
+ * [WordPress Multisite Features](http://www.wpwhitesecurity.com/wordpress-plugins/wordpress-user-monitoring-plugin/wp-security-audit-log-plugin-features-wordpress-multisite/)
118
+ * [WP Security Audit Log and Reverse Proxy and WAFs Support](http://www.wpwhitesecurity.com/wordpress-plugins/wordpress-user-monitoring-plugin/wp-security-audit-log-plugin-retrieves-originating-wordpress-user-ip-address/)
119
  * [Official WP Security Audit Log Page](http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/)
120
+
121
+ = WordPress Security Tips & Tricks =
122
+ Even if WordPress security is not your cup of tea, the security of your WordPress is your responsibility. Keep yourself up to date with the latest WordPress Security Tips & Tricks. WP White Security frequently publishes WordPress security tips & tricks on the [WordPress Security section](http://www.wpwhitesecurity.com/wordpress-security/) of their blog.
123
 
124
  = Plugin Newsletter =
125
  To keep yourself updated with what is new and updated in our WordPress security plugins please subscribe to the [WP White Security Plugins Newsletter](http://eepurl.com/Jn9sP).
164
 
165
  == Changelog ==
166
 
167
+ = 1.3.2 (2014-12-16) =
168
+ * **New Features and Options**
169
+ * Plugin automatically retrieves user's originating IP address even if WordPress is installed behind a reverse proxy, web application firewall or load balancer. For more information refer to [WP Security Audit Log, Reverse Proxies and WAFs](http://www.wpwhitesecurity.com/wordpress-plugins/wordpress-user-monitoring-plugin/wp-security-audit-log-plugin-retrieves-originating-wordpress-user-ip-address/)
170
+ * New option to omit internal IP addresses from being reported in the WordPress security audit log
171
+
172
+ * **Removed Functionality**
173
+ * The sandbox was removed from the plugin. If you need to use the sandbox for troubleshooting and tested contact us since we migrated it to a standalone extension.
174
+
175
+ * **Bug Fixes**
176
+ * Fixed a bug where site administrators where not able to view the WordPress security alerts for their sites in a WordPress multisite installation
177
+ * Improved some SQL queries as reported in this [support ticket](https://wordpress.org/support/topic/syntax-error-d-not-replaced?replies=10#post-6278773)
178
+ * Fixed an issue with alerts pruning (when pruning was set by number of alerts the plugin was pruning all alerts)
179
+
180
  = 1.3.1 (2014-11-27) =
181
  * **New WordPress Security Alerts**
182
  * Alert 2065: The content of published post has been modified
wp-security-audit-log.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: WP Security Audit Log
4
  Plugin URI: http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/
5
  Description: Identify WordPress security issues before they become a problem and keep track of everything happening on your WordPress, including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log will generate a security alert for everything that happens on your WordPress blog or website. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  Author: WP White Security
7
- Version: 1.3.1
8
  Text Domain: wp-security-audit-log
9
  Author URI: http://www.wpwhitesecurity.com/
10
  License: GPL2
4
  Plugin URI: http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/
5
  Description: Identify WordPress security issues before they become a problem and keep track of everything happening on your WordPress, including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log will generate a security alert for everything that happens on your WordPress blog or website. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  Author: WP White Security
7
+ Version: 1.3.2
8
  Text Domain: wp-security-audit-log
9
  Author URI: http://www.wpwhitesecurity.com/
10
  License: GPL2