WP Security Audit Log - Version 2.1.0

Version Description

(2015-09-09) = * New Features * Support for the External DB Add-on. * Integration with WhatIsMyIPAddress.com (Click an IP addresses in Audit Log viewer to get all information about it). * Settings to Incude or exclude specific columns from the Audit Log viewer. * Ability to exclude an IP address from monitoring * New option to disable the reporting of WordPress background tasks (such as deletion of auto draft posts)

  • Bug Fixes
    • Fixed a problem when trying to customize a widget via the theme customizer support ticket.
    • Handling an error that was generated when someone logged in to a WordPress via social media channels.
    • Fixed: incorrect alert generated when a widget is moved from the bottom of a container to another.
    • Fixed: incorrect alert generated when a custom filed is deleted from a page.
    • Fixed an issue where post related actions were not reported for users with author and contributor roles.
    • Fixed an issue where in a specific scenario the settings in the options tabel were duplicate.
Download this release

Release Info

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

Code changes from version 2.0.1 to 2.1.0

classes/AlertManager.php CHANGED
@@ -1,350 +1,364 @@
1
  <?php
2
 
3
  final class WSAL_AlertManager {
4
-
5
- /**
6
- * @var WSAL_Alert[]
7
- */
8
- protected $_alerts = array();
9
-
10
- /**
11
- * @var WSAL_AbstractLogger[]
12
- */
13
- protected $_loggers = array();
14
-
15
- /**
16
- * @var WpSecurityAuditLog
17
- */
18
- protected $plugin;
19
 
20
- /**
21
- * Create new AlertManager instance.
22
- * @param WpSecurityAuditLog $plugin
23
- */
24
- public function __construct(WpSecurityAuditLog $plugin){
25
- $this->plugin = $plugin;
26
- foreach(glob(dirname(__FILE__) . '/Loggers/*.php') as $file)
27
- $this->AddFromFile($file);
28
-
29
- add_action('shutdown', array($this, '_CommitPipeline'));
30
- }
31
 
32
- /**
33
- * Add new logger from file inside autoloader path.
34
- * @param string $file Path to file.
35
- */
36
- public function AddFromFile($file){
37
- $this->AddFromClass($this->plugin->GetClassFileClassName($file));
38
- }
39
-
40
- /**
41
- * Add new logger given class name.
42
- * @param string $class Class name.
43
- */
44
- public function AddFromClass($class){
45
- $this->AddInstance(new $class($this->plugin));
46
- }
47
-
48
- /**
49
- * Add newly created logger to list.
50
- * @param WSAL_AbstractLogger $logger The new logger.
51
- */
52
- public function AddInstance(WSAL_AbstractLogger $logger){
53
- $this->_loggers[] = $logger;
54
- }
55
-
56
- /**
57
- * Remove logger by class name.
58
- * @param string $class The class name.
59
- */
60
- public function RemoveByClass($class){
61
- foreach($this->_loggers as $i => $inst)
62
- if(get_class($inst) == $class)
63
- unset($this->_loggers[$i]);
64
- }
65
-
66
- /**
67
- * Contains a list of alerts to trigger.
68
- * @var array
69
- */
70
- protected $_pipeline = array();
71
-
72
- /**
73
- * Contains an array of alerts that have been triggered for this request.
74
- * @var int[]
75
- */
76
- protected $_triggered_types = array();
77
-
78
- /**
79
- * Trigger an alert.
80
- * @param integer $type Alert type.
81
- * @param array $data Alert data.
82
- */
83
- public function Trigger($type, $data = array(), $delayed = false){
84
- $username = wp_get_current_user()->user_login;
85
- if (empty($username) && !empty($data["Username"])) {
86
- $username = $data['Username'];
87
- }
88
- $roles = $this->plugin->settings->GetCurrentUserRoles();
89
- if (empty($roles) && !empty($data["CurrentUserRoles"])) {
90
- $roles = $data['CurrentUserRoles'];
91
- }
92
- if ( $this->CheckEnableUserRoles($username, $roles) ) {
93
- if ($delayed) {
94
- $this->TriggerIf($type, $data, null);
95
- } else {
96
- $this->_CommitItem($type, $data, null);
97
- }
98
- }
99
- }
 
 
 
100
 
101
- /**
102
- * Check enable user and roles.
103
- * @param string user
104
- * @param array roles
105
- * @return boolean True if enable false otherwise.
106
- */
107
- public function CheckEnableUserRoles($user, $roles) {
108
- $is_enable = true;
109
- if ( $user != "" && $this->IsDisabledUser($user) ) { $is_enable = false; }
110
- if ( $roles != "" && $this->IsDisabledRole($roles) ) { $is_enable = false; }
111
- return $is_enable;
112
- }
113
-
114
- /**
115
- * Trigger only if a condition is met at the end of request.
116
- * @param integer $type Alert type ID.
117
- * @param array $data Alert data.
118
- * @param callable $cond A future condition callback (receives an object of type WSAL_AlertManager as parameter).
119
- */
120
- public function TriggerIf($type, $data, $cond = null) {
121
- $username = wp_get_current_user()->user_login;
122
- $roles = $this->plugin->settings->GetCurrentUserRoles();
123
-
124
- if ($this->CheckEnableUserRoles($username, $roles)) {
125
- $this->_pipeline[] = array(
126
- 'type' => $type,
127
- 'data' => $data,
128
- 'cond' => $cond,
129
- );
130
- }
131
- }
132
-
133
- /**
134
- * @internal Commit an alert now.
135
- */
136
- protected function _CommitItem($type, $data, $cond, $_retry = true)
137
- {
138
- if(!$cond || !!call_user_func($cond, $this)){
139
- if($this->IsEnabled($type)) {
140
- if(isset($this->_alerts[$type])){
141
- // ok, convert alert to a log entry
142
- $this->_triggered_types[] = $type;
143
- $this->Log($type, $data);
144
- }elseif($_retry){
145
- // this is the last attempt at loading alerts from default file
146
- $this->plugin->LoadDefaults();
147
- return $this->_CommitItem($type, $data, $cond, false);
148
- }else{
149
- // in general this shouldn't happen, but it could, so we handle it here :)
150
- throw new Exception('Alert with code "' . $type . '" has not be registered.');
151
- }
152
- }
153
- }
154
- }
155
-
156
- /**
157
- * @internal Runs over triggered alerts in pipeline and passes them to loggers.
158
- */
159
- public function _CommitPipeline(){
160
- foreach($this->_pipeline as $item)
161
- $this->_CommitItem($item['type'], $item['data'], $item['cond']);
162
- }
163
-
164
- /**
165
- * @param integer $type Alert type ID.
166
- * @return boolean True if at the end of request an alert of this type will be triggered.
167
- */
168
- public function WillTrigger($type){
169
- foreach($this->_pipeline as $item)
170
- if($item['type'] == $type)
171
- return true;
172
- return false;
173
- }
174
-
175
- /**
176
- * @param int $type Alert type ID.
177
- * @return boolean True if an alert has been or will be triggered in this request, false otherwise.
178
- */
179
- public function WillOrHasTriggered($type){
180
- return in_array($type, $this->_triggered_types)
181
- || $this->WillTrigger($type);
182
- }
183
-
184
- /**
185
- * Register an alert type.
186
- * @param array $info Array of [type, code, category, description, message] respectively.
187
- */
188
- public function Register($info){
189
- if(func_num_args() == 1){
190
- // handle single item
191
- list($type, $code, $catg, $desc, $mesg) = $info;
192
- if(isset($this->_alerts[$type]))
193
- throw new Exception("Alert $type already registered with Alert Manager.");
194
- $this->_alerts[$type] = new WSAL_Alert($type, $code, $catg, $desc, $mesg);
195
- }else{
196
- // handle multiple items
197
- foreach(func_get_args() as $arg)
198
- $this->Register($arg);
199
- }
200
- }
201
-
202
- /**
203
- * Register a whole group of items.
204
- * @param array $groups An array with group name as the index and an array of group items as the value.
205
- * Item values is an array of [type, code, description, message] respectively.
206
- */
207
- public function RegisterGroup($groups){
208
- foreach($groups as $name => $group){
209
- foreach($group as $item){
210
- list($type, $code, $desc, $mesg) = $item;
211
- $this->Register(array($type, $code, $name, $desc, $mesg));
212
- }
213
- }
214
- }
215
-
216
- /**
217
- * Returns whether alert of type $type is enabled or not.
218
- * @param integer $type Alert type.
219
- * @return boolean True if enabled, false otherwise.
220
- */
221
- public function IsEnabled($type){
222
- return !in_array($type, $this->GetDisabledAlerts());
223
- }
224
-
225
- /**
226
- * Disables a set of alerts by type.
227
- * @param int[] $types Alert type codes to be disabled.
228
- */
229
- public function SetDisabledAlerts($types){
230
- $this->plugin->settings->SetDisabledAlerts($types);
231
- }
232
-
233
- /**
234
- * @return int[] Returns an array of disabled alerts' type code.
235
- */
236
- public function GetDisabledAlerts(){
237
- return $this->plugin->settings->GetDisabledAlerts();
238
- }
239
-
240
- /**
241
- * @return WSAL_AbstractLogger[] Returns an array of loaded loggers.
242
- */
243
- public function GetLoggers(){
244
- return $this->_loggers;
245
- }
246
-
247
- /**
248
- * Converts an Alert into a Log entry (by invoking loggers).
249
- * You should not call this method directly.
250
- * @param integer $type Alert type.
251
- * @param array $data Misc alert data.
252
- */
253
- protected function Log($type, $data = array()){
254
- if(!isset($data['ClientIP']))
255
- $data['ClientIP'] = $this->plugin->settings->GetMainClientIP();
256
- if(!isset($data['OtherIPs']) && $this->plugin->settings->IsMainIPFromProxy())
257
- $data['OtherIPs'] = $this->plugin->settings->GetClientIPs();
258
- if(!isset($data['UserAgent']))
259
- $data['UserAgent'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
260
- if(!isset($data['Username']) && !isset($data['CurrentUserID']))
261
- $data['CurrentUserID'] = function_exists('get_current_user_id') ? get_current_user_id() : 0;
262
- if(!isset($data['CurrentUserRoles']) && function_exists('is_user_logged_in') && is_user_logged_in())
263
- $data['CurrentUserRoles'] = $this->plugin->settings->GetCurrentUserRoles();
264
-
265
- //if(isset($_SERVER['REMOTE_HOST']) && $_SERVER['REMOTE_HOST'] != $data['ClientIP'])
266
- // $data['ClientHost'] = $_SERVER['REMOTE_HOST'];
267
-
268
- //$data['OtherIPs'] = $_SERVER['REMOTE_HOST'];
269
-
270
- foreach($this->_loggers as $logger)
271
- $logger->Log($type, $data);
272
- }
273
-
274
- /**
275
- * Return alert given alert type.
276
- * @param integer $type Alert type.
277
- * @param mixed $default Returned if alert is not found.
278
- * @return WSAL_Alert
279
- */
280
- public function GetAlert($type, $default = null){
281
- foreach($this->_alerts as $alert)
282
- if($alert->type == $type)
283
- return $alert;
284
- return $default;
285
- }
286
-
287
- /**
288
- * Returns all supported alerts.
289
- * @return WSAL_Alert[]
290
- */
291
- public function GetAlerts(){
292
- return $this->_alerts;
293
- }
294
-
295
- /**
296
- * Returns all supported alerts.
297
- * @return array
298
- */
299
- public function GetCategorizedAlerts(){
300
- $result = array();
301
- foreach($this->_alerts as $alert){
302
- if(!isset($result[$alert->catg]))
303
- $result[$alert->catg] = array();
304
- $result[$alert->catg][] = $alert;
305
- }
306
- ksort($result);
307
- return $result;
308
- }
309
 
310
- /**
311
- * Returns whether user is enabled or not.
312
- * @param string user.
313
- * @return boolean True if disabled, false otherwise.
314
- */
315
- public function IsDisabledUser($user)
316
- {
317
- return (in_array($user, $this->GetDisabledUsers())) ? true : false;
318
- }
319
-
320
- /**
321
- * @return Returns an array of disabled users.
322
- */
323
- public function GetDisabledUsers()
324
- {
325
- return $this->plugin->settings->GetExcludedMonitoringUsers();
326
- }
327
 
328
- /**
329
- * Returns whether user is enabled or not.
330
- * @param array roles.
331
- * @return boolean True if disabled, false otherwise.
332
- */
333
- public function IsDisabledRole($roles)
334
- {
335
- $is_disabled = false;
336
- foreach ($roles as $role) {
337
- if(in_array($role, $this->GetDisabledRoles())) $is_disabled = true;
338
- }
339
- return $is_disabled;
340
- }
341
-
342
- /**
343
- * @return Returns an array of disabled users.
344
- */
345
- public function GetDisabledRoles()
346
- {
347
- return $this->plugin->settings->GetExcludedMonitoringRoles();
348
- }
349
-
350
- }
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
 
3
  final class WSAL_AlertManager {
4
+
5
+ /**
6
+ * @var WSAL_Alert[]
7
+ */
8
+ protected $_alerts = array();
9
+
10
+ /**
11
+ * @var WSAL_AbstractLogger[]
12
+ */
13
+ protected $_loggers = array();
14
+
15
+ /**
16
+ * @var WpSecurityAuditLog
17
+ */
18
+ protected $plugin;
19
 
20
+ /**
21
+ * Create new AlertManager instance.
22
+ * @param WpSecurityAuditLog $plugin
23
+ */
24
+ public function __construct(WpSecurityAuditLog $plugin){
25
+ $this->plugin = $plugin;
26
+ foreach(glob(dirname(__FILE__) . '/Loggers/*.php') as $file)
27
+ $this->AddFromFile($file);
28
+
29
+ add_action('shutdown', array($this, '_CommitPipeline'));
30
+ }
31
 
32
+ /**
33
+ * Add new logger from file inside autoloader path.
34
+ * @param string $file Path to file.
35
+ */
36
+ public function AddFromFile($file){
37
+ $this->AddFromClass($this->plugin->GetClassFileClassName($file));
38
+ }
39
+
40
+ /**
41
+ * Add new logger given class name.
42
+ * @param string $class Class name.
43
+ */
44
+ public function AddFromClass($class){
45
+ $this->AddInstance(new $class($this->plugin));
46
+ }
47
+
48
+ /**
49
+ * Add newly created logger to list.
50
+ * @param WSAL_AbstractLogger $logger The new logger.
51
+ */
52
+ public function AddInstance(WSAL_AbstractLogger $logger){
53
+ $this->_loggers[] = $logger;
54
+ }
55
+
56
+ /**
57
+ * Remove logger by class name.
58
+ * @param string $class The class name.
59
+ */
60
+ public function RemoveByClass($class){
61
+ foreach($this->_loggers as $i => $inst)
62
+ if(get_class($inst) == $class)
63
+ unset($this->_loggers[$i]);
64
+ }
65
+
66
+ /**
67
+ * Contains a list of alerts to trigger.
68
+ * @var array
69
+ */
70
+ protected $_pipeline = array();
71
+
72
+ /**
73
+ * Contains an array of alerts that have been triggered for this request.
74
+ * @var int[]
75
+ */
76
+ protected $_triggered_types = array();
77
+
78
+ /**
79
+ * Trigger an alert.
80
+ * @param integer $type Alert type.
81
+ * @param array $data Alert data.
82
+ */
83
+ public function Trigger($type, $data = array(), $delayed = false){
84
+ $username = wp_get_current_user()->user_login;
85
+ if (empty($username) && !empty($data["Username"])) {
86
+ $username = $data['Username'];
87
+ }
88
+ $roles = $this->plugin->settings->GetCurrentUserRoles();
89
+ if (empty($roles) && !empty($data["CurrentUserRoles"])) {
90
+ $roles = $data['CurrentUserRoles'];
91
+ }
92
+ if ($this->IsDisabledIP()) {
93
+ return;
94
+ }
95
+ if ($this->CheckEnableUserRoles($username, $roles)) {
96
+ if ($delayed) {
97
+ $this->TriggerIf($type, $data, null);
98
+ } else {
99
+ $this->_CommitItem($type, $data, null);
100
+ }
101
+ }
102
+ }
103
 
104
+ /**
105
+ * Check enable user and roles.
106
+ * @param string user
107
+ * @param array roles
108
+ * @return boolean True if enable false otherwise.
109
+ */
110
+ public function CheckEnableUserRoles($user, $roles) {
111
+ $is_enable = true;
112
+ if ( $user != "" && $this->IsDisabledUser($user) ) { $is_enable = false; }
113
+ if ( $roles != "" && $this->IsDisabledRole($roles) ) { $is_enable = false; }
114
+ return $is_enable;
115
+ }
116
+
117
+ /**
118
+ * Trigger only if a condition is met at the end of request.
119
+ * @param integer $type Alert type ID.
120
+ * @param array $data Alert data.
121
+ * @param callable $cond A future condition callback (receives an object of type WSAL_AlertManager as parameter).
122
+ */
123
+ public function TriggerIf($type, $data, $cond = null) {
124
+ $username = wp_get_current_user()->user_login;
125
+ $roles = $this->plugin->settings->GetCurrentUserRoles();
126
+
127
+ if ($this->CheckEnableUserRoles($username, $roles)) {
128
+ $this->_pipeline[] = array(
129
+ 'type' => $type,
130
+ 'data' => $data,
131
+ 'cond' => $cond,
132
+ );
133
+ }
134
+ }
135
+
136
+ /**
137
+ * @internal Commit an alert now.
138
+ */
139
+ protected function _CommitItem($type, $data, $cond, $_retry = true)
140
+ {
141
+ if(!$cond || !!call_user_func($cond, $this)){
142
+ if($this->IsEnabled($type)) {
143
+ if(isset($this->_alerts[$type])){
144
+ // ok, convert alert to a log entry
145
+ $this->_triggered_types[] = $type;
146
+ $this->Log($type, $data);
147
+ }elseif($_retry){
148
+ // this is the last attempt at loading alerts from default file
149
+ $this->plugin->LoadDefaults();
150
+ return $this->_CommitItem($type, $data, $cond, false);
151
+ }else{
152
+ // in general this shouldn't happen, but it could, so we handle it here :)
153
+ throw new Exception('Alert with code "' . $type . '" has not be registered.');
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ /**
160
+ * @internal Runs over triggered alerts in pipeline and passes them to loggers.
161
+ */
162
+ public function _CommitPipeline(){
163
+ foreach($this->_pipeline as $item)
164
+ $this->_CommitItem($item['type'], $item['data'], $item['cond']);
165
+ }
166
+
167
+ /**
168
+ * @param integer $type Alert type ID.
169
+ * @return boolean True if at the end of request an alert of this type will be triggered.
170
+ */
171
+ public function WillTrigger($type){
172
+ foreach($this->_pipeline as $item)
173
+ if($item['type'] == $type)
174
+ return true;
175
+ return false;
176
+ }
177
+
178
+ /**
179
+ * @param int $type Alert type ID.
180
+ * @return boolean True if an alert has been or will be triggered in this request, false otherwise.
181
+ */
182
+ public function WillOrHasTriggered($type){
183
+ return in_array($type, $this->_triggered_types)
184
+ || $this->WillTrigger($type);
185
+ }
186
+
187
+ /**
188
+ * Register an alert type.
189
+ * @param array $info Array of [type, code, category, description, message] respectively.
190
+ */
191
+ public function Register($info){
192
+ if(func_num_args() == 1){
193
+ // handle single item
194
+ list($type, $code, $catg, $desc, $mesg) = $info;
195
+ if(isset($this->_alerts[$type]))
196
+ throw new Exception("Alert $type already registered with Alert Manager.");
197
+ $this->_alerts[$type] = new WSAL_Alert($type, $code, $catg, $desc, $mesg);
198
+ }else{
199
+ // handle multiple items
200
+ foreach(func_get_args() as $arg)
201
+ $this->Register($arg);
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Register a whole group of items.
207
+ * @param array $groups An array with group name as the index and an array of group items as the value.
208
+ * Item values is an array of [type, code, description, message] respectively.
209
+ */
210
+ public function RegisterGroup($groups){
211
+ foreach($groups as $name => $group){
212
+ foreach($group as $item){
213
+ list($type, $code, $desc, $mesg) = $item;
214
+ $this->Register(array($type, $code, $name, $desc, $mesg));
215
+ }
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Returns whether alert of type $type is enabled or not.
221
+ * @param integer $type Alert type.
222
+ * @return boolean True if enabled, false otherwise.
223
+ */
224
+ public function IsEnabled($type){
225
+ return !in_array($type, $this->GetDisabledAlerts());
226
+ }
227
+
228
+ /**
229
+ * Disables a set of alerts by type.
230
+ * @param int[] $types Alert type codes to be disabled.
231
+ */
232
+ public function SetDisabledAlerts($types){
233
+ $this->plugin->settings->SetDisabledAlerts($types);
234
+ }
235
+
236
+ /**
237
+ * @return int[] Returns an array of disabled alerts' type code.
238
+ */
239
+ public function GetDisabledAlerts(){
240
+ return $this->plugin->settings->GetDisabledAlerts();
241
+ }
242
+
243
+ /**
244
+ * @return WSAL_AbstractLogger[] Returns an array of loaded loggers.
245
+ */
246
+ public function GetLoggers(){
247
+ return $this->_loggers;
248
+ }
249
+
250
+ /**
251
+ * Converts an Alert into a Log entry (by invoking loggers).
252
+ * You should not call this method directly.
253
+ * @param integer $type Alert type.
254
+ * @param array $data Misc alert data.
255
+ */
256
+ protected function Log($type, $data = array()){
257
+ if(!isset($data['ClientIP']))
258
+ $data['ClientIP'] = $this->plugin->settings->GetMainClientIP();
259
+ if(!isset($data['OtherIPs']) && $this->plugin->settings->IsMainIPFromProxy())
260
+ $data['OtherIPs'] = $this->plugin->settings->GetClientIPs();
261
+ if(!isset($data['UserAgent']))
262
+ $data['UserAgent'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
263
+ if(!isset($data['Username']) && !isset($data['CurrentUserID']))
264
+ $data['CurrentUserID'] = function_exists('get_current_user_id') ? get_current_user_id() : 0;
265
+ if(!isset($data['CurrentUserRoles']) && function_exists('is_user_logged_in') && is_user_logged_in())
266
+ $data['CurrentUserRoles'] = $this->plugin->settings->GetCurrentUserRoles();
267
+
268
+ //if(isset($_SERVER['REMOTE_HOST']) && $_SERVER['REMOTE_HOST'] != $data['ClientIP'])
269
+ // $data['ClientHost'] = $_SERVER['REMOTE_HOST'];
270
+
271
+ //$data['OtherIPs'] = $_SERVER['REMOTE_HOST'];
272
+
273
+ foreach($this->_loggers as $logger)
274
+ $logger->Log($type, $data);
275
+ }
276
+
277
+ /**
278
+ * Return alert given alert type.
279
+ * @param integer $type Alert type.
280
+ * @param mixed $default Returned if alert is not found.
281
+ * @return WSAL_Alert
282
+ */
283
+ public function GetAlert($type, $default = null){
284
+ foreach($this->_alerts as $alert)
285
+ if($alert->type == $type)
286
+ return $alert;
287
+ return $default;
288
+ }
289
+
290
+ /**
291
+ * Returns all supported alerts.
292
+ * @return WSAL_Alert[]
293
+ */
294
+ public function GetAlerts(){
295
+ return $this->_alerts;
296
+ }
297
+
298
+ /**
299
+ * Returns all supported alerts.
300
+ * @return array
301
+ */
302
+ public function GetCategorizedAlerts(){
303
+ $result = array();
304
+ foreach($this->_alerts as $alert){
305
+ if(!isset($result[$alert->catg]))
306
+ $result[$alert->catg] = array();
307
+ $result[$alert->catg][] = $alert;
308
+ }
309
+ ksort($result);
310
+ return $result;
311
+ }
312
 
313
+ /**
314
+ * Returns whether user is enabled or not.
315
+ * @param string user.
316
+ * @return boolean True if disabled, false otherwise.
317
+ */
318
+ public function IsDisabledUser($user)
319
+ {
320
+ return (in_array($user, $this->GetDisabledUsers())) ? true : false;
321
+ }
322
+
323
+ /**
324
+ * @return Returns an array of disabled users.
325
+ */
326
+ public function GetDisabledUsers()
327
+ {
328
+ return $this->plugin->settings->GetExcludedMonitoringUsers();
329
+ }
330
 
331
+ /**
332
+ * Returns whether user is enabled or not.
333
+ * @param array roles.
334
+ * @return boolean True if disabled, false otherwise.
335
+ */
336
+ public function IsDisabledRole($roles)
337
+ {
338
+ $is_disabled = false;
339
+ foreach ($roles as $role) {
340
+ if(in_array($role, $this->GetDisabledRoles())) $is_disabled = true;
341
+ }
342
+ return $is_disabled;
343
+ }
344
+
345
+ /**
346
+ * @return Returns an array of disabled users.
347
+ */
348
+ public function GetDisabledRoles()
349
+ {
350
+ return $this->plugin->settings->GetExcludedMonitoringRoles();
351
+ }
352
+
353
+ private function IsDisabledIP()
354
+ {
355
+ $is_disabled = false;
356
+ $ip = $this->plugin->settings->GetMainClientIP();
357
+ $excluded_ips = $this->plugin->settings->GetExcludedMonitoringIP();
358
+ if (in_array($ip, $excluded_ips)) {
359
+ $is_disabled = true;
360
+ }
361
+ return $is_disabled;
362
+ }
363
+
364
+ }
classes/AuditLogListView.php CHANGED
@@ -5,366 +5,394 @@ require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
5
 
6
  class WSAL_AuditLogListView extends WP_List_Table {
7
 
8
- /**
9
- * @var WpSecurityAuditLog
10
- */
11
- protected $_plugin;
12
-
13
- public function __construct($plugin){
14
- $this->_plugin = $plugin;
15
-
16
- $this->_gmt_offset_sec = get_option('gmt_offset') * HOUR_IN_SECONDS;
17
-
18
- parent::__construct(array(
19
- 'singular' => 'log',
20
- 'plural' => 'logs',
21
- 'ajax' => true,
22
- 'screen' => 'interval-list',
23
- ));
24
- }
25
-
26
- protected $_gmt_offset_sec = 0;
27
 
28
- public function no_items(){
29
- _e('No events so far.', 'wp-security-audit-log');
30
- }
31
-
32
- public function extra_tablenav($which){
33
- // items-per-page widget
34
- $o = __('Other', 'wp-security-audit-log');
35
- $p = $this->_plugin->settings->GetViewPerPage();
36
- $items = array($o, 5, 10, 15, 30, 50);
37
- if (!in_array($p, $items)) $items[] = $p;
38
- if ($p == $o || $p == 0) $p = $o[1]; // a sane default if things goes bust
39
-
40
- ?><div class="wsal-ipp wsal-ipp-<?php echo $which; ?>">
41
- <?php _e('Show ', 'wp-security-audit-log'); ?>
42
- <select class="wsal-ipps" onfocus="WsalIppsFocus(value);" onchange="WsalIppsChange(value);">
43
- <?php foreach($items as $item){ ?>
44
- <option
45
- value="<?php echo is_string($item) ? '' : $item; ?>"
46
- <?php if($item == $p)echo 'selected="selected"'; ?>><?php
47
- echo $item;
48
- ?></option>
49
- <?php } ?>
50
- </select>
51
- <?php _e(' Items', 'wp-security-audit-log'); ?>
52
- </div><?php
53
-
54
- // show site alerts widget
55
- if($this->is_multisite() && $this->is_main_blog()){
56
- $curr = $this->get_view_site_id();
57
- ?><div class="wsal-ssa wsal-ssa-<?php echo $which; ?>">
58
- <?php if($this->get_site_count() > 15){ ?>
59
- <?php $curr = $curr ? get_blog_details($curr) : null; ?>
60
- <?php $curr = $curr ? ($curr->blogname . ' (' . $curr->domain . ')') : 'All Sites'; ?>
61
- <input type="text" class="wsal-ssas" value="<?php echo esc_attr($curr); ?>"/>
62
- <?php }else{ ?>
63
- <select class="wsal-ssas" onchange="WsalSsasChange(value);">
64
- <option value="0"><?php _e('All Sites', 'wp-security-audit-log'); ?></option>
65
- <?php foreach($this->get_sites() as $info){ ?>
66
- <option value="<?php echo $info->blog_id; ?>"
67
- <?php if($info->blog_id == $curr)echo 'selected="selected"'; ?>><?php
68
- echo esc_html($info->blogname) . ' (' . esc_html($info->domain) . ')';
69
- ?></option>
70
- <?php } ?>
71
- </select>
72
- <?php } ?>
73
- </div><?php
74
- }
75
- }
76
-
77
- /**
78
- * @param int|null $limit Maximum number of sites to return (null = no limit).
79
- * @return object Object with keys: blog_id, blogname, domain
80
- */
81
- public function get_sites($limit = null){
82
- global $wpdb;
83
-
84
- // build query
85
- $sql = 'SELECT blog_id, domain FROM ' . $wpdb->blogs;
86
- if(!is_null($limit))$sql .= ' LIMIT ' . $limit;
87
-
88
- // execute query
89
- $res = $wpdb->get_results($sql);
90
-
91
- // modify result
92
- foreach($res as $row){
93
- $row->blogname = get_blog_option($row->blog_id, 'blogname');
94
- }
95
-
96
- // return result
97
- return $res;
98
- }
99
-
100
- /**
101
- * @return int The number of sites on the network.
102
- */
103
- public function get_site_count(){
104
- global $wpdb;
105
- $sql = 'SELECT COUNT(*) FROM ' . $wpdb->blogs;
106
- return (int)$wpdb->get_var($sql);
107
- }
108
 
109
- public function get_columns(){
110
- $cols = array(
111
- //'cb' => '<input type="checkbox" />',
112
- //'read' => __('Read', 'wp-security-audit-log'),
113
- 'type' => __('Code', 'wp-security-audit-log'),
114
- 'code' => __('Type', 'wp-security-audit-log'),
115
- 'crtd' => __('Date', 'wp-security-audit-log'),
116
- 'user' => __('Username', 'wp-security-audit-log'),
117
- 'scip' => __('Source IP', 'wp-security-audit-log'),
118
- );
119
- if($this->is_multisite() && $this->is_main_blog() && !$this->is_specific_view()){
120
- $cols['site'] = __('Site', 'wp-security-audit-log');
121
- }
122
- $cols['mesg'] = __('Message', 'wp-security-audit-log');
123
- if($this->_plugin->settings->IsDataInspectorEnabled()){
124
- $cols['data'] = '';
125
- }
126
- return $cols;
127
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
- public function column_cb($item){
130
- return '<input type="checkbox" value="'.$item->id.'" '
131
- . 'name="'.esc_attr($this->_args['singular']).'[]"/>';
132
- }
133
 
134
- public function get_sortable_columns(){
135
- return array(
136
- 'read' => array('is_read', false),
137
- //'code' => array('code', false),
138
- 'type' => array('alert_id', false),
139
- 'crtd' => array('created_on', true),
140
- 'user' => array('user', true),
141
- 'scip' => array('scip', false)
142
- );
143
- }
144
-
145
- public function column_default($item, $column_name){
146
- //example: $item->getMetaValue('CurrentUserID')
147
 
148
- if (!$this->_plugin->settings->GetDatetimeFormat()) $datetimeFormat = 'h:i:s.$$$&\n\b\s\p;A';
149
- else $datetimeFormat = 'H:i:s.$$$';
150
- switch($column_name){
151
- case 'read':
152
- return '<span class="log-read log-read-'
153
- . ($item->is_read ? 'old' : 'new')
154
- . '" title="' . __('Click to toggle.', 'wp-security-audit-log') . '"></span>';
155
- case 'type':
156
- return str_pad($item->alert_id, 4, '0', STR_PAD_LEFT);
157
- case 'code':
158
- $code = $this->_plugin->alerts->GetAlert($item->alert_id);
159
- $code = $code ? $code->code : 0;
160
- $const = (object)array('name' => 'E_UNKNOWN', 'value' => 0, 'description' => __('Unknown error code.', 'wp-security-audit-log'));
161
- $const = $this->_plugin->constants->GetConstantBy('value', $code, $const);
162
- return '<span class="log-type log-type-' . $const->value
163
- . '" title="' . esc_html($const->name . ': ' . $const->description) . '"></span>';
164
- case 'crtd':
165
- return $item->created_on ? (
166
- str_replace(
167
- '$$$',
168
- substr(number_format(fmod($item->created_on + $this->_gmt_offset_sec, 1), 3), 2),
169
- date('Y-m-d<\b\r>'.$datetimeFormat, $item->created_on + $this->_gmt_offset_sec)
170
- )
171
- ) : '<i>unknown</i>';
172
- case 'user':
173
- $username = $item->GetUsername();
174
- if ($username && ($user = get_user_by('login', $username))) {
175
- $image = get_avatar($user->ID, 32);
176
- $uhtml = '<a href="' . admin_url('user-edit.php?user_id=' . $user->ID)
177
- . '" target="_blank">' . esc_html($user->display_name) . '</a>';
178
- $roles = $item->GetUserRoles();
179
- if (is_array($roles) && count($roles)) {
180
- $roles = __(esc_html(ucwords(implode(', ', $roles))));
181
- } else if (is_string($roles) && $roles != '') {
182
- $roles = __(esc_html(ucwords(str_replace(array("\"", "[", "]"), " ", $roles))));
183
- } else {
184
- $roles = '<i>' . __('Unknown', 'wp-security-audit-log') . '</i>';
185
- }
186
- } else {
187
- $image = get_avatar(0, 32);
188
- $uhtml = '<i>' . __('Unknown', 'wp-security-audit-log') . '</i>';
189
- $roles = '<i>' . __('System', 'wp-security-audit-log') . '</i>';
190
- }
191
- return $image . $uhtml . '<br/>' . $roles;
192
- case 'scip':
193
- $scip = $item->GetSourceIP();
194
- if (is_string($scip)) {
195
- $scip = str_replace(array("\"", "[", "]"), "", $scip);
196
- }
197
- $oips = array(); //$item->GetOtherIPs();
198
- // if there's no IP...
199
- if (is_null($scip) || $scip == '') return '<i>unknown</i>';
200
- // if there's only one IP...
201
- if (count($oips) < 2) return esc_html($scip);
202
- // if there are many IPs...
203
- $html = esc_html($scip) . ' <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
204
- foreach($oips as $ip)if($scip!=$ip)$html .= '<div>' . $ip . '</div>';
205
- $html .= '</div>';
206
- return $html;
207
- case 'site':
208
- $info = get_blog_details($item->site_id, true);
209
- return !$info ? ('Unknown Site '.$item->site_id)
210
- : ('<a href="' . esc_attr($info->siteurl) . '">' . esc_html($info->blogname) . '</a>');
211
- case 'mesg':
212
- return '<div id="Event' . $item->id . '">' . $item->GetMessage(array($this, 'meta_formatter')) . '</div>';
213
- case 'data':
214
- $url = admin_url('admin-ajax.php') . '?action=AjaxInspector&amp;occurrence=' . $item->id;
215
- return '<a class="more-info thickbox" title="' . __('Alert Data Inspector', 'wp-security-audit-log') . '"'
216
- . ' href="' . $url . '&amp;TB_iframe=true&amp;width=600&amp;height=550">&hellip;</a>';
217
- default:
218
- return isset($item->$column_name)
219
- ? esc_html($item->$column_name)
220
- : 'Column "' . esc_html($column_name) . '" not found';
221
- }
222
- }
 
223
 
224
- public function reorder_items_str($a, $b){
225
- $result = strcmp($a->{$this->_orderby}, $b->{$this->_orderby});
226
- return ($this->_order === 'asc') ? $result : -$result;
227
- }
228
-
229
- public function reorder_items_int($a, $b){
230
- $result = $a->{$this->_orderby} - $b->{$this->_orderby};
231
- return ($this->_order === 'asc') ? $result : -$result;
232
- }
233
-
234
- public function meta_formatter($name, $value){
235
- switch(true){
236
-
237
- case $name == '%Message%':
238
- return esc_html($value);
239
 
240
- case $name == '%MetaLink%':
241
- if (!empty($value)) {
242
- return "<a href=\"#\" onclick=\"WsalDisableCustom(this, '".$value."');\"> Exclude Custom Field from the Monitoring</a>";
243
- } else {
244
- return "";
245
- }
246
- case in_array($name, array('%MetaValue%', '%MetaValueOld%', '%MetaValueNew%')):
247
- return '<strong>' . (
248
- strlen($value) > 50 ? (esc_html(substr($value, 0, 50)) . '&hellip;') : esc_html($value)
249
- ) . '</strong>';
250
-
251
- case strncmp($value, 'http://', 7) === 0:
252
- case strncmp($value, 'https://', 7) === 0:
253
- return '<a href="' . esc_html($value) . '"'
254
- . ' title="' . esc_html($value) . '"'
255
- . ' target="_blank">'
256
- . esc_html(parse_url($value, PHP_URL_HOST)) . '/&hellip;/'
257
- . esc_html(basename(parse_url($value, PHP_URL_PATH)))
258
- . '</a>';
259
-
260
- default:
261
- return '<strong>' . esc_html($value) . '</strong>';
262
- }
263
- }
264
-
265
- protected function is_multisite(){
266
- return $this->_plugin->IsMultisite();
267
- }
268
-
269
- protected function is_main_blog(){
270
- return get_current_blog_id() == 1;
271
- }
272
-
273
- protected function is_specific_view(){
274
- return isset($_REQUEST['wsal-cbid']) && $_REQUEST['wsal-cbid'] != '0';
275
- }
276
-
277
- protected function get_specific_view(){
278
- return isset($_REQUEST['wsal-cbid']) ? (int)$_REQUEST['wsal-cbid'] : 0;
279
- }
280
-
281
- protected function get_view_site_id(){
282
- switch(true){
283
-
284
- // non-multisite
285
- case !$this->is_multisite():
286
- return 0;
287
-
288
- // multisite + main site view
289
- case $this->is_main_blog() && !$this->is_specific_view():
290
- return 0;
291
-
292
- // multisite + switched site view
293
- case $this->is_main_blog() && $this->is_specific_view():
294
- return $this->get_specific_view();
295
-
296
- // multisite + local site view
297
- default:
298
- return get_current_blog_id();
299
-
300
- }
301
- }
302
-
303
- public function prepare_items() {
304
- $per_page = $this->_plugin->settings->GetViewPerPage();
305
 
306
- $columns = $this->get_columns();
307
- $hidden = array();
308
- $sortable = $this->get_sortable_columns();
309
 
310
- $this->_column_headers = array($columns, $hidden, $sortable);
311
 
312
- //$this->process_bulk_action();
313
-
314
- //TO DO: Get rid of OccurrenceQuery and use the Occurence Model
315
- $query = new WSAL_Models_OccurrenceQuery();
316
 
317
- $bid = (int)$this->get_view_site_id();
318
- if ($bid) {
319
- $query->addCondition("site_id = %s ", $bid);
320
- }
321
-
322
- $query = apply_filters('wsal_auditlog_query', $query);
323
-
324
- $total_items = $query->getAdapter()->Count($query);
325
 
326
- if (empty($_REQUEST["orderby"])) {
327
- $query->addOrderBy("created_on", true);
328
- } else {
329
- $orderByField = $_REQUEST["orderby"];
330
 
331
- $isDescending = true;
332
- if (!empty($_REQUEST['order']) && $_REQUEST["order"] == "asc") {
333
- $isDescending = false;
334
- }
335
 
336
- //TO DO: Allow order by meta values
337
- if ($orderByField == "scip") {
338
- $query->addMetaJoin();
339
- $query->addOrderBy('CASE WHEN meta.name = "ClientIP" THEN meta.value END', $isDescending);
340
- } else if ($orderByField == "user") {
341
- $query->addMetaJoin();
342
- $query->addOrderBy('CASE WHEN meta.name = "CurrentUserID" THEN meta.value END', $isDescending);
343
- } else {
344
- $tmp = new WSAL_Models_Occurrence();
345
- //Making sure the field exists to order by
346
- if (isset($tmp->{$orderByField})) {
347
- // TODO we used to use a custom comparator ... is it safe to let MySQL do the ordering now?
348
- $query->addOrderBy($_REQUEST["orderby"], $isDescending);
349
 
350
- } else {
351
- $query->addOrderBy("created_on", true);
352
- }
353
- }
354
- }
355
 
356
- /** @todo Modify $query instead */
357
- /** @deprecated */
358
- //$data = array_slice($data, ($this->get_pagenum() - 1) * $per_page, $per_page);
359
- $query->setOffset(($this->get_pagenum() - 1) * $per_page);
360
- $query->setLimit($per_page);
361
 
362
- $this->items = $query->getAdapter()->Execute($query);
363
 
364
- $this->set_pagination_args( array(
365
- 'total_items' => $total_items,
366
- 'per_page' => $per_page,
367
- 'total_pages' => ceil($total_items / $per_page)
368
- ) );
369
- }
370
  }
5
 
6
  class WSAL_AuditLogListView extends WP_List_Table {
7
 
8
+ /**
9
+ * @var WpSecurityAuditLog
10
+ */
11
+ protected $_plugin;
12
+
13
+ public function __construct($plugin){
14
+ $this->_plugin = $plugin;
15
+
16
+ $this->_gmt_offset_sec = get_option('gmt_offset') * HOUR_IN_SECONDS;
17
+
18
+ parent::__construct(array(
19
+ 'singular' => 'log',
20
+ 'plural' => 'logs',
21
+ 'ajax' => true,
22
+ 'screen' => 'interval-list',
23
+ ));
24
+ }
25
+
26
+ protected $_gmt_offset_sec = 0;
27
 
28
+ public function no_items(){
29
+ _e('No events so far.', 'wp-security-audit-log');
30
+ }
31
+
32
+ public function extra_tablenav($which){
33
+ // items-per-page widget
34
+ $o = __('Other', 'wp-security-audit-log');
35
+ $p = $this->_plugin->settings->GetViewPerPage();
36
+ $items = array($o, 5, 10, 15, 30, 50);
37
+ if (!in_array($p, $items)) $items[] = $p;
38
+ if ($p == $o || $p == 0) $p = $o[1]; // a sane default if things goes bust
39
+
40
+ ?><div class="wsal-ipp wsal-ipp-<?php echo $which; ?>">
41
+ <?php _e('Show ', 'wp-security-audit-log'); ?>
42
+ <select class="wsal-ipps" onfocus="WsalIppsFocus(value);" onchange="WsalIppsChange(value);">
43
+ <?php foreach($items as $item){ ?>
44
+ <option
45
+ value="<?php echo is_string($item) ? '' : $item; ?>"
46
+ <?php if($item == $p)echo 'selected="selected"'; ?>><?php
47
+ echo $item;
48
+ ?></option>
49
+ <?php } ?>
50
+ </select>
51
+ <?php _e(' Items', 'wp-security-audit-log'); ?>
52
+ </div><?php
53
+
54
+ // show site alerts widget
55
+ if($this->is_multisite() && $this->is_main_blog()){
56
+ $curr = $this->get_view_site_id();
57
+ ?><div class="wsal-ssa wsal-ssa-<?php echo $which; ?>">
58
+ <?php if($this->get_site_count() > 15){ ?>
59
+ <?php $curr = $curr ? get_blog_details($curr) : null; ?>
60
+ <?php $curr = $curr ? ($curr->blogname . ' (' . $curr->domain . ')') : 'All Sites'; ?>
61
+ <input type="text" class="wsal-ssas" value="<?php echo esc_attr($curr); ?>"/>
62
+ <?php }else{ ?>
63
+ <select class="wsal-ssas" onchange="WsalSsasChange(value);">
64
+ <option value="0"><?php _e('All Sites', 'wp-security-audit-log'); ?></option>
65
+ <?php foreach($this->get_sites() as $info){ ?>
66
+ <option value="<?php echo $info->blog_id; ?>"
67
+ <?php if($info->blog_id == $curr)echo 'selected="selected"'; ?>><?php
68
+ echo esc_html($info->blogname) . ' (' . esc_html($info->domain) . ')';
69
+ ?></option>
70
+ <?php } ?>
71
+ </select>
72
+ <?php } ?>
73
+ </div><?php
74
+ }
75
+ }
76
+
77
+ /**
78
+ * @param int|null $limit Maximum number of sites to return (null = no limit).
79
+ * @return object Object with keys: blog_id, blogname, domain
80
+ */
81
+ public function get_sites($limit = null){
82
+ global $wpdb;
83
+
84
+ // build query
85
+ $sql = 'SELECT blog_id, domain FROM ' . $wpdb->blogs;
86
+ if(!is_null($limit))$sql .= ' LIMIT ' . $limit;
87
+
88
+ // execute query
89
+ $res = $wpdb->get_results($sql);
90
+
91
+ // modify result
92
+ foreach($res as $row){
93
+ $row->blogname = get_blog_option($row->blog_id, 'blogname');
94
+ }
95
+
96
+ // return result
97
+ return $res;
98
+ }
99
+
100
+ /**
101
+ * @return int The number of sites on the network.
102
+ */
103
+ public function get_site_count(){
104
+ global $wpdb;
105
+ $sql = 'SELECT COUNT(*) FROM ' . $wpdb->blogs;
106
+ return (int)$wpdb->get_var($sql);
107
+ }
108
 
109
+ public function get_columns(){
110
+ $cols = array(
111
+ //'cb' => '<input type="checkbox" />',
112
+ //'read' => __('Read', 'wp-security-audit-log'),
113
+ 'type' => __('Code', 'wp-security-audit-log'),
114
+ 'code' => __('Type', 'wp-security-audit-log'),
115
+ 'crtd' => __('Date', 'wp-security-audit-log'),
116
+ 'user' => __('Username', 'wp-security-audit-log'),
117
+ 'scip' => __('Source IP', 'wp-security-audit-log'),
118
+ );
119
+ if($this->is_multisite() && $this->is_main_blog() && !$this->is_specific_view()){
120
+ $cols['site'] = __('Site', 'wp-security-audit-log');
121
+ }
122
+ $cols['mesg'] = __('Message', 'wp-security-audit-log');
123
+ if($this->_plugin->settings->IsDataInspectorEnabled()){
124
+ $cols['data'] = '';
125
+ }
126
+ $sel_columns = $this->_plugin->settings->GetColumnsSelected();
127
+ if (!empty($sel_columns)) {
128
+ unset($cols);
129
+ $sel_columns = (array)json_decode($sel_columns);
130
+ foreach ($sel_columns as $key => $value) {
131
+ switch ($key) {
132
+ case 'alert_code':
133
+ $cols['type'] = __('Code', 'wp-security-audit-log');
134
+ break;
135
+ case 'type':
136
+ $cols['code'] = __('Type', 'wp-security-audit-log');
137
+ break;
138
+ case 'date':
139
+ $cols['crtd'] = __('Date', 'wp-security-audit-log');
140
+ break;
141
+ case 'username':
142
+ $cols['user'] = __('Username', 'wp-security-audit-log');
143
+ break;
144
+ case 'source_ip':
145
+ $cols['scip'] = __('Source IP', 'wp-security-audit-log');
146
+ break;
147
+ case 'message':
148
+ $cols['mesg'] = __('Message', 'wp-security-audit-log');
149
+ break;
150
+ }
151
+ }
152
+ }
153
+ return $cols;
154
+ }
155
 
156
+ public function column_cb($item){
157
+ return '<input type="checkbox" value="'.$item->id.'" '
158
+ . 'name="'.esc_attr($this->_args['singular']).'[]"/>';
159
+ }
160
 
161
+ public function get_sortable_columns(){
162
+ return array(
163
+ 'read' => array('is_read', false),
164
+ //'code' => array('code', false),
165
+ 'type' => array('alert_id', false),
166
+ 'crtd' => array('created_on', true),
167
+ 'user' => array('user', true),
168
+ 'scip' => array('scip', false)
169
+ );
170
+ }
171
+
172
+ public function column_default($item, $column_name){
173
+ //example: $item->getMetaValue('CurrentUserID')
174
 
175
+ if (!$this->_plugin->settings->GetDatetimeFormat()) $datetimeFormat = 'h:i:s.$$$&\n\b\s\p;A';
176
+ else $datetimeFormat = 'H:i:s.$$$';
177
+ switch($column_name){
178
+ case 'read':
179
+ return '<span class="log-read log-read-'
180
+ . ($item->is_read ? 'old' : 'new')
181
+ . '" title="' . __('Click to toggle.', 'wp-security-audit-log') . '"></span>';
182
+ case 'type':
183
+ return str_pad($item->alert_id, 4, '0', STR_PAD_LEFT);
184
+ case 'code':
185
+ $code = $this->_plugin->alerts->GetAlert($item->alert_id);
186
+ $code = $code ? $code->code : 0;
187
+ $const = (object)array('name' => 'E_UNKNOWN', 'value' => 0, 'description' => __('Unknown error code.', 'wp-security-audit-log'));
188
+ $const = $this->_plugin->constants->GetConstantBy('value', $code, $const);
189
+ return '<span class="log-type log-type-' . $const->value
190
+ . '" title="' . esc_html($const->name . ': ' . $const->description) . '"></span>';
191
+ case 'crtd':
192
+ return $item->created_on ? (
193
+ str_replace(
194
+ '$$$',
195
+ substr(number_format(fmod($item->created_on + $this->_gmt_offset_sec, 1), 3), 2),
196
+ date('Y-m-d<\b\r>'.$datetimeFormat, $item->created_on + $this->_gmt_offset_sec)
197
+ )
198
+ ) : '<i>unknown</i>';
199
+ case 'user':
200
+ $username = $item->GetUsername();
201
+ if ($username && ($user = get_user_by('login', $username))) {
202
+ $image = get_avatar($user->ID, 32);
203
+ $uhtml = '<a href="' . admin_url('user-edit.php?user_id=' . $user->ID)
204
+ . '" target="_blank">' . esc_html($user->display_name) . '</a>';
205
+ $roles = $item->GetUserRoles();
206
+ if (is_array($roles) && count($roles)) {
207
+ $roles = __(esc_html(ucwords(implode(', ', $roles))));
208
+ } else if (is_string($roles) && $roles != '') {
209
+ $roles = __(esc_html(ucwords(str_replace(array("\"", "[", "]"), " ", $roles))));
210
+ } else {
211
+ $roles = '<i>' . __('Unknown', 'wp-security-audit-log') . '</i>';
212
+ }
213
+ } else {
214
+ $image = get_avatar(0, 32);
215
+ $uhtml = '<i>' . __('Unknown', 'wp-security-audit-log') . '</i>';
216
+ $roles = '<i>' . __('System', 'wp-security-audit-log') . '</i>';
217
+ }
218
+ return $image . $uhtml . '<br/>' . $roles;
219
+ case 'scip':
220
+ $scip = $item->GetSourceIP();
221
+ if (is_string($scip)) {
222
+ $scip = str_replace(array("\"", "[", "]"), "", $scip);
223
+ }
224
+ $oips = array(); //$item->GetOtherIPs();
225
+ // if there's no IP...
226
+ if (is_null($scip) || $scip == '') return '<i>unknown</i>';
227
+ // if there's only one IP...
228
+ $link = "http://whatismyipaddress.com/ip/" . $scip ."?utm_source=plugin&utm_medium=referral&utm_campaign=WPSAL";
229
+ if (count($oips) < 2) return "<a target='_blank' href='$link'>". esc_html($scip) .'</a>';
230
+ // if there are many IPs...
231
+ $html = "<a target='_blank' href='http://whatismyipaddress.com/ip/$scip'>". esc_html($scip) .'</a>'.' <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
232
+ foreach($oips as $ip)if($scip!=$ip)$html .= '<div>' . $ip . '</div>';
233
+ $html .= '</div>';
234
+ return $html;
235
+ case 'site':
236
+ $info = get_blog_details($item->site_id, true);
237
+ return !$info ? ('Unknown Site '.$item->site_id)
238
+ : ('<a href="' . esc_attr($info->siteurl) . '">' . esc_html($info->blogname) . '</a>');
239
+ case 'mesg':
240
+ return '<div id="Event' . $item->id . '">' . $item->GetMessage(array($this, 'meta_formatter')) . '</div>';
241
+ case 'data':
242
+ $url = admin_url('admin-ajax.php') . '?action=AjaxInspector&amp;occurrence=' . $item->id;
243
+ return '<a class="more-info thickbox" title="' . __('Alert Data Inspector', 'wp-security-audit-log') . '"'
244
+ . ' href="' . $url . '&amp;TB_iframe=true&amp;width=600&amp;height=550">&hellip;</a>';
245
+ default:
246
+ return isset($item->$column_name)
247
+ ? esc_html($item->$column_name)
248
+ : 'Column "' . esc_html($column_name) . '" not found';
249
+ }
250
+ }
251
 
252
+ public function reorder_items_str($a, $b){
253
+ $result = strcmp($a->{$this->_orderby}, $b->{$this->_orderby});
254
+ return ($this->_order === 'asc') ? $result : -$result;
255
+ }
256
+
257
+ public function reorder_items_int($a, $b){
258
+ $result = $a->{$this->_orderby} - $b->{$this->_orderby};
259
+ return ($this->_order === 'asc') ? $result : -$result;
260
+ }
261
+
262
+ public function meta_formatter($name, $value){
263
+ switch(true){
264
+
265
+ case $name == '%Message%':
266
+ return esc_html($value);
267
 
268
+ case $name == '%MetaLink%':
269
+ if (!empty($value)) {
270
+ return "<a href=\"#\" onclick=\"WsalDisableCustom(this, '".$value."');\"> Exclude Custom Field from the Monitoring</a>";
271
+ } else {
272
+ return "";
273
+ }
274
+ case in_array($name, array('%MetaValue%', '%MetaValueOld%', '%MetaValueNew%')):
275
+ return '<strong>' . (
276
+ strlen($value) > 50 ? (esc_html(substr($value, 0, 50)) . '&hellip;') : esc_html($value)
277
+ ) . '</strong>';
278
+
279
+ case strncmp($value, 'http://', 7) === 0:
280
+ case strncmp($value, 'https://', 7) === 0:
281
+ return '<a href="' . esc_html($value) . '"'
282
+ . ' title="' . esc_html($value) . '"'
283
+ . ' target="_blank">'
284
+ . esc_html(parse_url($value, PHP_URL_HOST)) . '/&hellip;/'
285
+ . esc_html(basename(parse_url($value, PHP_URL_PATH)))
286
+ . '</a>';
287
+
288
+ default:
289
+ return '<strong>' . esc_html($value) . '</strong>';
290
+ }
291
+ }
292
+
293
+ protected function is_multisite(){
294
+ return $this->_plugin->IsMultisite();
295
+ }
296
+
297
+ protected function is_main_blog(){
298
+ return get_current_blog_id() == 1;
299
+ }
300
+
301
+ protected function is_specific_view(){
302
+ return isset($_REQUEST['wsal-cbid']) && $_REQUEST['wsal-cbid'] != '0';
303
+ }
304
+
305
+ protected function get_specific_view(){
306
+ return isset($_REQUEST['wsal-cbid']) ? (int)$_REQUEST['wsal-cbid'] : 0;
307
+ }
308
+
309
+ protected function get_view_site_id(){
310
+ switch(true){
311
+
312
+ // non-multisite
313
+ case !$this->is_multisite():
314
+ return 0;
315
+
316
+ // multisite + main site view
317
+ case $this->is_main_blog() && !$this->is_specific_view():
318
+ return 0;
319
+
320
+ // multisite + switched site view
321
+ case $this->is_main_blog() && $this->is_specific_view():
322
+ return $this->get_specific_view();
323
+
324
+ // multisite + local site view
325
+ default:
326
+ return get_current_blog_id();
327
+
328
+ }
329
+ }
330
+
331
+ public function prepare_items() {
332
+ $per_page = $this->_plugin->settings->GetViewPerPage();
333
 
334
+ $columns = $this->get_columns();
335
+ $hidden = array();
336
+ $sortable = $this->get_sortable_columns();
337
 
338
+ $this->_column_headers = array($columns, $hidden, $sortable);
339
 
340
+ //$this->process_bulk_action();
341
+
342
+ //TO DO: Get rid of OccurrenceQuery and use the Occurence Model
343
+ $query = new WSAL_Models_OccurrenceQuery();
344
 
345
+ $bid = (int)$this->get_view_site_id();
346
+ if ($bid) {
347
+ $query->addCondition("site_id = %s ", $bid);
348
+ }
349
+
350
+ $query = apply_filters('wsal_auditlog_query', $query);
351
+
352
+ $total_items = $query->getAdapter()->Count($query);
353
 
354
+ if (empty($_REQUEST["orderby"])) {
355
+ $query->addOrderBy("created_on", true);
356
+ } else {
357
+ $orderByField = $_REQUEST["orderby"];
358
 
359
+ $isDescending = true;
360
+ if (!empty($_REQUEST['order']) && $_REQUEST["order"] == "asc") {
361
+ $isDescending = false;
362
+ }
363
 
364
+ //TO DO: Allow order by meta values
365
+ if ($orderByField == "scip") {
366
+ $query->addMetaJoin();
367
+ $query->addOrderBy('CASE WHEN meta.name = "ClientIP" THEN meta.value END', $isDescending);
368
+ } else if ($orderByField == "user") {
369
+ $query->addMetaJoin();
370
+ $query->addOrderBy('CASE WHEN meta.name = "CurrentUserID" THEN meta.value END', $isDescending);
371
+ } else {
372
+ $tmp = new WSAL_Models_Occurrence();
373
+ //Making sure the field exists to order by
374
+ if (isset($tmp->{$orderByField})) {
375
+ // TODO we used to use a custom comparator ... is it safe to let MySQL do the ordering now?
376
+ $query->addOrderBy($_REQUEST["orderby"], $isDescending);
377
 
378
+ } else {
379
+ $query->addOrderBy("created_on", true);
380
+ }
381
+ }
382
+ }
383
 
384
+ /** @todo Modify $query instead */
385
+ /** @deprecated */
386
+ //$data = array_slice($data, ($this->get_pagenum() - 1) * $per_page, $per_page);
387
+ $query->setOffset(($this->get_pagenum() - 1) * $per_page);
388
+ $query->setLimit($per_page);
389
 
390
+ $this->items = $query->getAdapter()->Execute($query);
391
 
392
+ $this->set_pagination_args( array(
393
+ 'total_items' => $total_items,
394
+ 'per_page' => $per_page,
395
+ 'total_pages' => ceil($total_items / $per_page)
396
+ ) );
397
+ }
398
  }
classes/Connector/ConnectorFactory.php CHANGED
@@ -20,12 +20,16 @@ abstract class WSAL_Connector_ConnectorFactory
20
  * Returns a connector singleton
21
  * @return WSAL_Connector_ConnectorInterface
22
  */
23
- public static function GetConnector()
24
  {
25
- $connectionConfig = self::GetConfig();
 
 
 
 
 
26
  //TO DO: Load connection config
27
-
28
- if (self::$connector == null) {
29
  switch (strtolower($connectionConfig['type'])) {
30
  //TO DO: Add other connectors
31
  case 'mysql':
@@ -58,13 +62,7 @@ abstract class WSAL_Connector_ConnectorFactory
58
  public static function CheckConfig($type, $user, $password, $name, $hostname, $base_prefix)
59
  {
60
  $result = false;
61
- $config = array(
62
- 'user' => $user,
63
- 'password' => $password,
64
- 'name' => $name,
65
- 'hostname' => $hostname,
66
- 'base_prefix' => $base_prefix
67
- );
68
  switch (strtolower($type)) {
69
  //TO DO: Add other connectors
70
  case 'mysql':
@@ -74,4 +72,16 @@ abstract class WSAL_Connector_ConnectorFactory
74
  }
75
  return $result;
76
  }
 
 
 
 
 
 
 
 
 
 
 
 
77
  }
20
  * Returns a connector singleton
21
  * @return WSAL_Connector_ConnectorInterface
22
  */
23
+ public static function GetConnector($config = null)
24
  {
25
+ if (!empty($config)) {
26
+ $connectionConfig = $config;
27
+ } else {
28
+ $connectionConfig = self::GetConfig();
29
+ }
30
+
31
  //TO DO: Load connection config
32
+ if (self::$connector == null || !empty($config)) {
 
33
  switch (strtolower($connectionConfig['type'])) {
34
  //TO DO: Add other connectors
35
  case 'mysql':
62
  public static function CheckConfig($type, $user, $password, $name, $hostname, $base_prefix)
63
  {
64
  $result = false;
65
+ $config = self::GetConfigArray($type, $user, $password, $name, $hostname, $base_prefix);
 
 
 
 
 
 
66
  switch (strtolower($type)) {
67
  //TO DO: Add other connectors
68
  case 'mysql':
72
  }
73
  return $result;
74
  }
75
+
76
+ public static function GetConfigArray($type, $user, $password, $name, $hostname, $base_prefix)
77
+ {
78
+ return array(
79
+ 'type' => $type,
80
+ 'user' => $user,
81
+ 'password' => $password,
82
+ 'name' => $name,
83
+ 'hostname' => $hostname,
84
+ 'base_prefix' => $base_prefix
85
+ );
86
+ }
87
  }
classes/Connector/MySQLDBConnector.php CHANGED
@@ -6,6 +6,7 @@ require_once('AbstractConnector.php');
6
  class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements WSAL_Connector_ConnectorInterface
7
  {
8
  protected $connectionConfig = null;
 
9
  public function __construct($connectionConfig = null)
10
  {
11
  $this->connectionConfig = $connectionConfig;
@@ -13,18 +14,18 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
13
  require_once($this->getAdaptersDirectory() . '/OptionAdapter.php');
14
  }
15
 
16
- function test_wp_die_callback() {
17
  return array( $this, 'test_die_handler' );
18
  }
19
 
20
- function test_die_handler( $message, $title = '', $args = array() ) {
21
- throw new Exception("DB Connection failed");
22
  }
23
 
24
  public function TestConnection()
25
  {
26
  error_reporting(E_ALL ^ E_WARNING);
27
- add_filter( 'wp_die_handler', array( $this, 'test_wp_die_callback' ) );
28
  $connection = $this->createConnection();
29
  }
30
 
@@ -37,7 +38,8 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
37
  if (!empty($this->connectionConfig)) {
38
  //TO DO: Use the provided connection config
39
  $connectionConfig = $this->connectionConfig;
40
- $newWpdb = new wpdb($connectionConfig['user'], $connectionConfig['password'], $connectionConfig['name'], $connectionConfig['hostname']);
 
41
  $newWpdb->set_prefix($connectionConfig['base_prefix']);
42
  return $newWpdb;
43
  } else {
@@ -78,7 +80,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
78
  */
79
  public function isInstalled()
80
  {
81
- $wpdb = $this->getConnection();
82
  $table = $wpdb->base_prefix . 'wsal_occurrences';
83
  return ($wpdb->get_var('SHOW TABLES LIKE "'.$table.'"') == $table);
84
  }
@@ -96,16 +98,20 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
96
  /**
97
  * Install all DB tables.
98
  */
99
- public function installAll()
100
  {
101
  $plugin = WpSecurityAuditLog::GetInstance();
102
 
103
  foreach (glob($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php') as $file) {
104
- $filePath = explode(DIRECTORY_SEPARATOR, $file);
105
  $fileName = $filePath[count($filePath) - 1];
106
  $className = $this->getAdapterClassName(str_replace("Adapter.php", "", $fileName));
107
-
108
  $class = new $className($this->getConnection());
 
 
 
 
109
  if (is_subclass_of($class, "WSAL_Adapters_MySQL_ActiveRecord")) {
110
  $class->Install();
111
  }
@@ -120,7 +126,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
120
  $plugin = WpSecurityAuditLog::GetInstance();
121
 
122
  foreach (glob($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php') as $file) {
123
- $filePath = explode(DIRECTORY_SEPARATOR, $file);
124
  $fileName = $filePath[count($filePath) - 1];
125
  $className = $this->getAdapterClassName(str_replace("Adapter.php", "", $fileName));
126
 
@@ -130,5 +136,126 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
130
  }
131
  }
132
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  }
6
  class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements WSAL_Connector_ConnectorInterface
7
  {
8
  protected $connectionConfig = null;
9
+
10
  public function __construct($connectionConfig = null)
11
  {
12
  $this->connectionConfig = $connectionConfig;
14
  require_once($this->getAdaptersDirectory() . '/OptionAdapter.php');
15
  }
16
 
17
+ public function test_wp_die_callback() {
18
  return array( $this, 'test_die_handler' );
19
  }
20
 
21
+ public function test_die_handler($message, $title = '', $args = array()) {
22
+ throw new Exception("DB Connection failed");
23
  }
24
 
25
  public function TestConnection()
26
  {
27
  error_reporting(E_ALL ^ E_WARNING);
28
+ add_filter('wp_die_handler', array($this, 'test_wp_die_callback'));
29
  $connection = $this->createConnection();
30
  }
31
 
38
  if (!empty($this->connectionConfig)) {
39
  //TO DO: Use the provided connection config
40
  $connectionConfig = $this->connectionConfig;
41
+ $password = $this->decryptString($connectionConfig['password']);
42
+ $newWpdb = new wpdb($connectionConfig['user'], $password, $connectionConfig['name'], $connectionConfig['hostname']);
43
  $newWpdb->set_prefix($connectionConfig['base_prefix']);
44
  return $newWpdb;
45
  } else {
80
  */
81
  public function isInstalled()
82
  {
83
+ global $wpdb;
84
  $table = $wpdb->base_prefix . 'wsal_occurrences';
85
  return ($wpdb->get_var('SHOW TABLES LIKE "'.$table.'"') == $table);
86
  }
98
  /**
99
  * Install all DB tables.
100
  */
101
+ public function installAll($excludeOptions = false)
102
  {
103
  $plugin = WpSecurityAuditLog::GetInstance();
104
 
105
  foreach (glob($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php') as $file) {
106
+ $filePath = explode(DIRECTORY_SEPARATOR, $file);
107
  $fileName = $filePath[count($filePath) - 1];
108
  $className = $this->getAdapterClassName(str_replace("Adapter.php", "", $fileName));
109
+
110
  $class = new $className($this->getConnection());
111
+ if ($excludeOptions && $class instanceof WSAL_Adapters_MySQL_Option) {
112
+ continue;
113
+ }
114
+
115
  if (is_subclass_of($class, "WSAL_Adapters_MySQL_ActiveRecord")) {
116
  $class->Install();
117
  }
126
  $plugin = WpSecurityAuditLog::GetInstance();
127
 
128
  foreach (glob($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php') as $file) {
129
+ $filePath = explode(DIRECTORY_SEPARATOR, $file);
130
  $fileName = $filePath[count($filePath) - 1];
131
  $className = $this->getAdapterClassName(str_replace("Adapter.php", "", $fileName));
132
 
136
  }
137
  }
138
  }
139
+
140
+ public function Migrate()
141
+ {
142
+ global $wpdb;
143
+ $_wpdb = $this->getConnection();
144
+
145
+ // Load data Occurrences from WP
146
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($wpdb);
147
+ if (!$occurrence->IsInstalled()) die("No alerts to import");
148
+ $sql = 'SELECT * FROM ' . $occurrence->GetWPTable();
149
+ $occurrences = $wpdb->get_results($sql, ARRAY_A);
150
+
151
+ // Insert data to External DB
152
+ $occurrenceNew = new WSAL_Adapters_MySQL_Occurrence($_wpdb);
153
+ $increase_id = 0;
154
+ $sql = 'SELECT MAX(id) FROM ' . $occurrenceNew->GetTable();
155
+ $increase_id = (int)$_wpdb->get_var($sql);
156
+
157
+ $sql = 'INSERT INTO ' . $occurrenceNew->GetTable() . ' (site_id, alert_id, created_on, is_read, is_migrated) VALUES ' ;
158
+ foreach ($occurrences as $entry) {
159
+ $sql .= '('.$entry['site_id'].', '.$entry['alert_id'].', '.$entry['created_on'].', '.$entry['is_read'].', 1), ';
160
+ }
161
+ $sql = rtrim($sql, ", ");
162
+ $_wpdb->query($sql);
163
+
164
+ // Load data Meta from WP
165
+ $meta = new WSAL_Adapters_MySQL_Meta($wpdb);
166
+ if (!$meta->IsInstalled()) die("No alerts to import");
167
+ $sql = 'SELECT * FROM ' . $meta->GetWPTable();
168
+ $metadata = $wpdb->get_results($sql, ARRAY_A);
169
+
170
+ // Insert data to External DB
171
+ $metaNew = new WSAL_Adapters_MySQL_Meta($_wpdb);
172
+ $sql = 'INSERT INTO ' . $metaNew->GetTable() . ' (occurrence_id, name, value) VALUES ' ;
173
+ foreach ($metadata as $entry) {
174
+ $occurrence_id = $entry['occurrence_id'] + $increase_id;
175
+ $sql .= '('.$occurrence_id.', \''.$entry['name'].'\', \''.$entry['value'].'\'), ';
176
+ }
177
+ $sql = rtrim($sql, ", ");
178
+ $_wpdb->query($sql);
179
+ $this->DeleteAfterMigrate($occurrence);
180
+ $this->DeleteAfterMigrate($meta);
181
+ }
182
+
183
+ public function MigrateBack()
184
+ {
185
+ global $wpdb;
186
+ $_wpdb = $this->getConnection();
187
+
188
+ // Load data Occurrences from External DB
189
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($_wpdb);
190
+ if (!$occurrence->IsInstalled()) die("No alerts to import");
191
+ $sql = 'SELECT * FROM ' . $occurrence->GetTable();
192
+ $occurrences = $_wpdb->get_results($sql, ARRAY_A);
193
+
194
+ // Insert data to WP
195
+ $occurrenceWP = new WSAL_Adapters_MySQL_Occurrence($wpdb);
196
+
197
+ $sql = 'INSERT INTO ' . $occurrenceWP->GetWPTable() . ' (site_id, alert_id, created_on, is_read, is_migrated) VALUES ' ;
198
+ foreach ($occurrences as $entry) {
199
+ $sql .= '('.$entry['site_id'].', '.$entry['alert_id'].', '.$entry['created_on'].', '.$entry['is_read'].', 1), ';
200
+ }
201
+ $sql = rtrim($sql, ", ");
202
+ $wpdb->query($sql);
203
+
204
+ // Load data Meta from External DB
205
+ $meta = new WSAL_Adapters_MySQL_Meta($_wpdb);
206
+ if (!$meta->IsInstalled()) die("No alerts to import");
207
+ $sql = 'SELECT * FROM ' . $meta->GetTable();
208
+ $metadata = $_wpdb->get_results($sql, ARRAY_A);
209
+
210
+ // Insert data to WP
211
+ $metaWP = new WSAL_Adapters_MySQL_Meta($wpdb);
212
+ $sql = 'INSERT INTO ' . $metaWP->GetWPTable() . ' (occurrence_id, name, value) VALUES ' ;
213
+ foreach ($metadata as $entry) {
214
+ $sql .= '('.$entry['occurrence_id'].', \''.$entry['name'].'\', \''.$entry['value'].'\'), ';
215
+ }
216
+ $sql = rtrim($sql, ", ");
217
+ $wpdb->query($sql);
218
+ }
219
+
220
+ private function DeleteAfterMigrate($record)
221
+ {
222
+ global $wpdb;
223
+ $sql = 'DROP TABLE IF EXISTS ' . $record->GetTable();
224
+ $wpdb->query($sql);
225
+ }
226
+
227
+ public function encryptString($plaintext)
228
+ {
229
+ $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
230
+ $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
231
+ $key = $this->truncateKey();
232
+ $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
233
+ $ciphertext = $iv . $ciphertext;
234
+ $ciphertext_base64 = base64_encode($ciphertext);
235
+
236
+ return $ciphertext_base64;
237
+ }
238
+
239
+ private function decryptString($ciphertext_base64)
240
+ {
241
+ $ciphertext_dec = base64_decode($ciphertext_base64);
242
+ $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
243
 
244
+ $iv_dec = substr($ciphertext_dec, 0, $iv_size);
245
+ $ciphertext_dec = substr($ciphertext_dec, $iv_size);
246
+ $key = $this->truncateKey();
247
+ $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
248
+
249
+ return rtrim($plaintext_dec, "\0");
250
+ }
251
+
252
+ private function truncateKey()
253
+ {
254
+ $key_size = strlen(AUTH_KEY);
255
+ if ($key_size > 32) {
256
+ return substr(AUTH_KEY, 0, 32);
257
+ } else {
258
+ return AUTH_KEY;
259
+ }
260
+ }
261
  }
classes/Models/Adapters/MySQL/ActiveRecordAdapter.php CHANGED
@@ -31,11 +31,20 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
31
  */
32
  public function GetTable()
33
  {
34
- //global $wpdb;
35
  $_wpdb = $this->connection;
36
  return $_wpdb->base_prefix . $this->_table;
37
  }
38
 
 
 
 
 
 
 
 
 
 
 
39
  /**
40
  * @return string SQL table options (constraints, foreign keys, indexes etc).
41
  */
@@ -68,17 +77,25 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
68
  //global $wpdb;
69
  $_wpdb = $this->connection;
70
  $sql = 'SHOW TABLES LIKE "' . $this->GetTable() . '"';
71
- return $_wpdb->get_var($sql) == $this->GetTable();
72
  }
73
 
74
  /**
75
  * Install this ActiveRecord structure into DB.
76
  */
77
  public function Install(){
78
- require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
79
- dbDelta($this->_GetInstallQuery());
80
  }
81
 
 
 
 
 
 
 
 
 
82
  /**
83
  * Remove this ActiveRecord structure into DB.
84
  */
@@ -86,7 +103,6 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
86
  {
87
  //global $wpdb;
88
  $_wpdb = $this->connection;
89
- require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
90
  $_wpdb->query($this->_GetUninstallQuery());
91
  }
92
 
@@ -276,18 +292,18 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
276
  /**
277
  * @return string Must return SQL for creating table.
278
  */
279
- protected function _GetInstallQuery()
280
  {
281
  $_wpdb = $this->connection;
282
 
283
  $class = get_class($this);
284
  $copy = new $class($this->connection);
285
-
286
- $sql = 'CREATE TABLE ' . $this->GetTable() . ' (' . PHP_EOL;
287
 
288
  foreach ($this->GetColumns() as $key) {
289
  $sql .= ' ';
290
- switch(true) {
291
  case $key == $copy->_idkey:
292
  $sql .= $key . ' BIGINT NOT NULL AUTO_INCREMENT,' . PHP_EOL;
293
  break;
@@ -455,6 +471,4 @@ query;
455
  */
456
  }
457
 
458
-
459
-
460
  }
31
  */
32
  public function GetTable()
33
  {
 
34
  $_wpdb = $this->connection;
35
  return $_wpdb->base_prefix . $this->_table;
36
  }
37
 
38
+ /**
39
+ * Used for WordPress prefix
40
+ * @return string Returns table name of WordPress.
41
+ */
42
+ public function GetWPTable()
43
+ {
44
+ global $wpdb;
45
+ return $wpdb->base_prefix . $this->_table;
46
+ }
47
+
48
  /**
49
  * @return string SQL table options (constraints, foreign keys, indexes etc).
50
  */
77
  //global $wpdb;
78
  $_wpdb = $this->connection;
79
  $sql = 'SHOW TABLES LIKE "' . $this->GetTable() . '"';
80
+ return strtolower($_wpdb->get_var($sql)) == strtolower($this->GetTable());
81
  }
82
 
83
  /**
84
  * Install this ActiveRecord structure into DB.
85
  */
86
  public function Install(){
87
+ $_wpdb = $this->connection;
88
+ $_wpdb->query($this->_GetInstallQuery());
89
  }
90
 
91
+ /**
92
+ * Install this ActiveRecord structure into DB WordPress.
93
+ */
94
+ public function InstallOriginal(){
95
+ global $wpdb;
96
+ $wpdb->query($this->_GetInstallQuery(true));
97
+ }
98
+
99
  /**
100
  * Remove this ActiveRecord structure into DB.
101
  */
103
  {
104
  //global $wpdb;
105
  $_wpdb = $this->connection;
 
106
  $_wpdb->query($this->_GetUninstallQuery());
107
  }
108
 
292
  /**
293
  * @return string Must return SQL for creating table.
294
  */
295
+ protected function _GetInstallQuery($prefix = false)
296
  {
297
  $_wpdb = $this->connection;
298
 
299
  $class = get_class($this);
300
  $copy = new $class($this->connection);
301
+ $table_name = ($prefix) ? $this->GetWPTable() : $this->GetTable();
302
+ $sql = 'CREATE TABLE IF NOT EXISTS ' . $table_name . ' (' . PHP_EOL;
303
 
304
  foreach ($this->GetColumns() as $key) {
305
  $sql .= ' ';
306
+ switch (true) {
307
  case $key == $copy->_idkey:
308
  $sql .= $key . ' BIGINT NOT NULL AUTO_INCREMENT,' . PHP_EOL;
309
  break;
471
  */
472
  }
473
 
 
 
474
  }
classes/Models/Adapters/MySQL/OptionAdapter.php CHANGED
@@ -16,7 +16,6 @@ class WSAL_Adapters_MySQL_Option extends WSAL_Adapters_MySQL_ActiveRecord
16
  parent::__construct($conn);
17
  }
18
 
19
-
20
  public function GetModel()
21
  {
22
  return new WSAL_Models_Option();
16
  parent::__construct($conn);
17
  }
18
 
 
19
  public function GetModel()
20
  {
21
  return new WSAL_Models_Option();
classes/Models/Option.php CHANGED
@@ -28,7 +28,7 @@ class WSAL_Models_Option extends WSAL_Models_ActiveRecord
28
 
29
  public function GetOptionValue($name, $default = array())
30
  {
31
- $option = $this->getAdapter()->GetNamedOption($name);
32
  $this->option_value = (!empty($option)) ? $option['option_value'] : null;
33
  if (!empty($this->option_value)) {
34
  $this->_state = self::STATE_LOADED;
28
 
29
  public function GetOptionValue($name, $default = array())
30
  {
31
+ $option = $this->getAdapter()->GetNamedOption($name);
32
  $this->option_value = (!empty($option)) ? $option['option_value'] : null;
33
  if (!empty($this->option_value)) {
34
  $this->_state = self::STATE_LOADED;
classes/Sensors/Content.php CHANGED
@@ -1,443 +1,509 @@
1
  <?php
2
 
3
- class WSAL_Sensors_Content extends WSAL_AbstractSensor {
 
4
 
5
- public function HookEvents() {
6
- if(current_user_can("manage_categories"))add_action('admin_init', array($this, 'EventWordpressInit'));
7
- add_action('transition_post_status', array($this, 'EventPostChanged'), 10, 3);
8
- add_action('delete_post', array($this, 'EventPostDeleted'), 10, 1);
9
- add_action('wp_trash_post', array($this, 'EventPostTrashed'), 10, 1);
10
- add_action('untrash_post', array($this, 'EventPostUntrashed'));
11
- add_action('edit_category', array($this, 'EventChangedCategoryParent'));
12
- }
13
-
14
- protected function GetEventTypeForPostType($post, $typePost, $typePage, $typeCustom){
15
- switch($post->post_type){
16
- case 'page':
17
- return $typePage;
18
- case 'post':
19
- return $typePost;
20
- default:
21
- return $typeCustom;
22
- }
23
- }
24
-
25
- protected $_OldPost = null;
26
- protected $_OldLink = null;
27
- protected $_OldCats = null;
28
- protected $_OldTmpl = null;
29
- protected $_OldStky = null;
30
-
31
- public function EventWordpressInit(){
32
- // load old data, if applicable
33
- $this->RetrieveOldData();
34
- // check for category changes
35
- $this->CheckCategoryCreation();
36
- $this->CheckCategoryDeletion();
37
- }
38
-
39
- protected function RetrieveOldData(){
 
 
 
 
 
 
40
  if (isset($_POST) && isset($_POST['post_ID'])
41
- && !(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
42
- && !(isset($_POST['action']) && $_POST['action'] == 'autosave')
43
- ){
44
- $postID = intval($_POST['post_ID']);
45
- $this->_OldPost = get_post($postID);
46
- $this->_OldLink = get_permalink($postID);
47
- $this->_OldTmpl = $this->GetPostTemplate($this->_OldPost);
48
- $this->_OldCats = $this->GetPostCategories($this->_OldPost);
49
- $this->_OldStky = in_array($postID, get_option('sticky_posts'));
50
- }
51
- }
52
-
53
- protected function GetPostTemplate($post){
54
- $id = $post->ID;
55
- $template = get_page_template_slug($id);
56
- $pagename = $post->post_name;
 
57
 
58
- $templates = array();
59
- if ( $template && 0 === validate_file( $template ) ) $templates[] = $template;
60
- if ( $pagename ) $templates[] = "page-$pagename.php";
61
- if ( $id ) $templates[] = "page-$id.php";
62
- $templates[] = 'page.php';
 
 
 
 
 
 
63
 
64
- return get_query_template( 'page', $templates );
65
- }
66
 
67
- protected function GetPostCategories($post){
68
- return wp_get_post_categories($post->ID, array('fields' => 'names'));
69
- }
 
70
 
71
- public function EventPostChanged($newStatus, $oldStatus, $post){
72
- // ignorable states
73
- if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
74
- if (empty($post->post_type)) return;
75
- if ($post->post_type == 'revision') return;
76
-
77
- $original = isset($_POST['original_post_status']) ? $_POST['original_post_status'] : '';
78
-
79
- WSAL_Sensors_Request::SetVars(array(
80
- '$newStatus' => $newStatus,
81
- '$oldStatus' => $oldStatus,
82
- '$original' => $original,
83
- ));
84
-
 
 
 
 
 
 
85
  // run checks
86
- if($this->_OldPost){
87
- if ($oldStatus == 'auto-draft' || $original == 'auto-draft'){
88
-
89
- // Handle create post events
90
- $this->CheckPostCreation($this->_OldPost, $post);
91
-
92
- }else{
93
-
94
- // Handle update post events
95
- $changes = 0
96
- + $this->CheckDateChange($this->_OldPost, $post)
97
- + $this->CheckAuthorChange($this->_OldPost, $post)
98
- + $this->CheckStatusChange($this->_OldPost, $post)
99
- + $this->CheckParentChange($this->_OldPost, $post)
100
- + $this->CheckStickyChange($this->_OldStky, isset($_REQUEST['sticky']), $post)
101
- + $this->CheckVisibilityChange($this->_OldPost, $post, $oldStatus, $newStatus)
102
- + $this->CheckTemplateChange($this->_OldTmpl, $this->GetPostTemplate($post), $post)
103
- + $this->CheckCategoriesChange($this->_OldCats, $this->GetPostCategories($post), $post)
104
- ;
105
- if(!$changes)
106
- $changes = $this->CheckPermalinkChange($this->_OldLink, get_permalink($post->ID), $post);
107
- if(!$changes)
108
- $changes = $this->CheckModificationChange($this->_OldPost, $post);
109
-
110
- }
111
- }
112
- }
113
-
114
- protected function CheckPostCreation($oldPost, $newPost){
115
- $event = 0;
116
- switch($newPost->post_status){
117
- case 'publish':
118
- $event = $this->GetEventTypeForPostType($oldPost, 2001, 2005, 2030);
119
- break;
120
- case 'draft':
121
- $event = $this->GetEventTypeForPostType($oldPost, 2000, 2004, 2029);
122
- break;
123
- }
124
- if($event)$this->plugin->alerts->Trigger($event, array(
125
- 'PostID' => $newPost->ID,
126
- 'PostType' => $newPost->post_type,
127
- 'PostTitle' => $newPost->post_title,
128
- 'PostUrl' => get_permalink($newPost->ID),
129
- ));
130
- }
131
-
132
- protected function CheckCategoryCreation(){
133
- if (empty($_POST)) return;
134
-
135
- $categoryName = '';
136
- if(!empty($_POST['screen']) && !empty($_POST['tag-name']) &&
137
- $_POST['screen'] == 'edit-category' &&
138
- $_POST['taxonomy'] == 'category' &&
139
- $_POST['action'] == 'add-tag')
140
- {
141
- $categoryName = $_POST['tag-name'];
142
- }
143
- elseif(!empty($_POST['newcategory']) && $_POST['action'] == 'add-category')
144
- {
145
- $categoryName = $_POST['newcategory'];
146
- }
147
-
148
- if($categoryName){
149
- $this->plugin->alerts->Trigger(2023, array(
150
- 'CategoryName' => $categoryName,
151
- ));
152
- }
153
- }
 
 
154
 
155
- protected function CheckCategoryDeletion(){
156
- if (empty($_POST)) return;
157
-
158
- $action = !empty($_POST['action']) ? $_POST['action']
159
- : (!empty($_POST['action2']) ? $_POST['action2'] : '');
160
- if (!$action) return;
 
 
 
 
161
 
162
- $categoryIds = array();
163
 
164
- if(isset($_POST['taxonomy'])){
165
- if($action == 'delete' && $_POST['taxonomy'] == 'category' && !empty($_POST['delete_tags'])){
166
- // bulk delete
167
- $categoryIds[] = $_POST['delete_tags'];
168
- }elseif($action == 'delete-tag' && $_POST['taxonomy'] == 'category' && !empty($_POST['tag_ID'])){
169
- // single delete
170
- $categoryIds[] = $_POST['tag_ID'];
171
- }
172
- }
173
 
174
- foreach($categoryIds as $categoryID){
175
- $category = get_category($categoryID);
176
- $this->plugin->alerts->Trigger(2024, array(
177
- 'CategoryID' => $categoryID,
178
- 'CategoryName' => $category->cat_name,
179
- ));
180
- }
181
- }
182
-
183
- public function EventPostDeleted($post_id){
184
- $post = get_post($post_id);
185
- if(!in_array($post->post_type, array('attachment', 'revision'))){ // ignore attachments and revisions
186
- $event = $this->GetEventTypeForPostType($post, 2008, 2009, 2033);
187
- $this->plugin->alerts->Trigger($event, array(
188
- 'PostID' => $post->ID,
189
- 'PostType' => $post->post_type,
190
- 'PostTitle' => $post->post_title,
191
- ));
192
- }
193
- }
194
-
195
- public function EventPostTrashed($post_id){
196
- $post = get_post($post_id);
197
- $event = $this->GetEventTypeForPostType($post, 2012, 2013, 2034);
198
- $this->plugin->alerts->Trigger($event, array(
199
- 'PostID' => $post->ID,
200
- 'PostType' => $post->post_type,
201
- 'PostTitle' => $post->post_title,
202
- ));
203
- }
204
-
205
- public function EventPostUntrashed($post_id){
206
- $post = get_post($post_id);
207
- $event = $this->GetEventTypeForPostType($post, 2014, 2015, 2035);
208
- $this->plugin->alerts->Trigger($event, array(
209
- 'PostID' => $post->ID,
210
- 'PostType' => $post->post_type,
211
- 'PostTitle' => $post->post_title,
212
- ));
213
- }
214
-
215
- protected function CheckDateChange($oldpost, $newpost){
 
 
 
 
 
 
 
 
216
  $from = strtotime($oldpost->post_date);
217
  $to = strtotime($newpost->post_date);
218
- if($oldpost->post_status == 'draft')return;
219
- if($from != $to){
220
- $event = $this->GetEventTypeForPostType($oldpost, 2027, 2028, 2041);
221
- $this->plugin->alerts->Trigger($event, array(
222
- 'PostID' => $oldpost->ID,
223
- 'PostType' => $oldpost->post_type,
224
- 'PostTitle' => $oldpost->post_title,
225
- 'OldDate' => $oldpost->post_date,
226
- 'NewDate' => $newpost->post_date,
227
- ));
228
- return 1;
229
- }
230
- }
231
-
232
- protected function CheckCategoriesChange($oldCats, $newCats, $post){
233
- $oldCats = implode(', ', $oldCats);
234
- $newCats = implode(', ', $newCats);
235
- if($oldCats != $newCats){
236
- $event = $this->GetEventTypeForPostType($post, 2016, 0, 2036);
237
- if($event){
238
- $this->plugin->alerts->Trigger($event, array(
239
- 'PostID' => $post->ID,
240
- 'PostType' => $post->post_type,
241
- 'PostTitle' => $post->post_title,
242
- 'OldCategories' => $oldCats ? $oldCats : 'no categories',
243
- 'NewCategories' => $newCats ? $newCats : 'no categories',
244
- ));
245
- return 1;
246
- }
247
- }
248
- }
249
-
250
- protected function CheckAuthorChange($oldpost, $newpost){
251
- if($oldpost->post_author != $newpost->post_author){
252
- $event = $this->GetEventTypeForPostType($oldpost, 2019, 2020, 2038);
253
- $this->plugin->alerts->Trigger($event, array(
254
- 'PostID' => $oldpost->ID,
255
- 'PostType' => $oldpost->post_type,
256
- 'PostTitle' => $oldpost->post_title,
257
- 'OldAuthor' => get_userdata($oldpost->post_author)->user_login,
258
- 'NewAuthor' => get_userdata($newpost->post_author)->user_login,
259
- ));
260
- return 1;
261
- }
262
- }
263
-
264
- protected function CheckStatusChange($oldpost, $newpost){
265
- if($oldpost->post_status != $newpost->post_status){
266
- if(isset($_REQUEST['publish'])){
267
- // special case (publishing a post)
268
- $event = $this->GetEventTypeForPostType($oldpost, 2001, 2005, 2030);
269
- $this->plugin->alerts->Trigger($event, array(
270
- 'PostID' => $newpost->ID,
271
- 'PostType' => $newpost->post_type,
272
- 'PostTitle' => $newpost->post_title,
273
- 'PostUrl' => get_permalink($newpost->ID),
274
- ));
275
- }else{
276
- $event = $this->GetEventTypeForPostType($oldpost, 2021, 2022, 2039);
277
- $this->plugin->alerts->Trigger($event, array(
278
- 'PostID' => $oldpost->ID,
279
- 'PostType' => $oldpost->post_type,
280
- 'PostTitle' => $oldpost->post_title,
281
- 'OldStatus' => $oldpost->post_status,
282
- 'NewStatus' => $newpost->post_status,
283
- ));
284
- }
285
- return 1;
286
- }
287
- }
288
-
289
- protected function CheckParentChange($oldpost, $newpost){
290
- if($oldpost->post_parent != $newpost->post_parent){
291
- $event = $this->GetEventTypeForPostType($oldpost, 0, 2047, 0);
292
- if($event){
293
- $this->plugin->alerts->Trigger($event, array(
294
- 'PostID' => $oldpost->ID,
295
- 'PostType' => $oldpost->post_type,
296
- 'PostTitle' => $oldpost->post_title,
297
- 'OldParent' => $oldpost->post_parent,
298
- 'NewParent' => $newpost->post_parent,
299
- 'OldParentName' => $oldpost->post_parent ? get_the_title($oldpost->post_parent) : 'no parent',
300
- 'NewParentName' => $newpost->post_parent ? get_the_title($newpost->post_parent) : 'no parent',
301
- ));
302
- return 1;
303
- }
304
- }
305
- }
306
-
307
- protected function CheckPermalinkChange($oldLink, $newLink, $post){
308
- if($oldLink != $newLink){
309
- $event = $this->GetEventTypeForPostType($post, 2017, 2018, 2037);
310
- $this->plugin->alerts->Trigger($event, array(
311
- 'PostID' => $post->ID,
312
- 'PostType' => $post->post_type,
313
- 'PostTitle' => $post->post_title,
314
- 'OldUrl' => $oldLink,
315
- 'NewUrl' => $newLink,
316
- ));
317
- return 1;
318
- }
319
- }
320
-
321
- protected function CheckVisibilityChange($oldpost, $newpost, $oldStatus, $newStatus){
322
- if($oldStatus == 'draft' || $newStatus == 'draft')return;
323
-
324
- $oldVisibility = '';
325
- $newVisibility = '';
326
-
327
- if($oldpost->post_password){
328
- $oldVisibility = __('Password Protected', 'wp-security-audit-log');
329
- }elseif($oldStatus == 'publish'){
330
- $oldVisibility = __('Public', 'wp-security-audit-log');
331
- }elseif($oldStatus == 'private'){
332
- $oldVisibility = __('Private', 'wp-security-audit-log');
333
- }
334
-
335
- if($newpost->post_password){
336
- $newVisibility = __('Password Protected', 'wp-security-audit-log');
337
- }elseif($newStatus == 'publish'){
338
- $newVisibility = __('Public', 'wp-security-audit-log');
339
- }elseif($newStatus == 'private'){
340
- $newVisibility = __('Private', 'wp-security-audit-log');
341
- }
342
-
343
- if($oldVisibility && $newVisibility && ($oldVisibility != $newVisibility)){
344
- $event = $this->GetEventTypeForPostType($oldpost, 2025, 2026, 2040);
345
- $this->plugin->alerts->Trigger($event, array(
346
- 'PostID' => $oldpost->ID,
347
- 'PostType' => $oldpost->post_type,
348
- 'PostTitle' => $oldpost->post_title,
349
- 'OldVisibility' => $oldVisibility,
350
- 'NewVisibility' => $newVisibility,
351
- ));
352
- return 1;
353
- }
354
- }
355
-
356
- protected function CheckTemplateChange($oldTmpl, $newTmpl, $post){
357
- if($oldTmpl != $newTmpl){
358
- $event = $this->GetEventTypeForPostType($post, 0, 2048, 0);
359
- if($event){
360
- $this->plugin->alerts->Trigger($event, array(
361
- 'PostID' => $post->ID,
362
- 'PostType' => $post->post_type,
363
- 'PostTitle' => $post->post_title,
364
- 'OldTemplate' => ucwords(str_replace(array('-' , '_'), ' ', basename($oldTmpl, '.php'))),
365
- 'NewTemplate' => ucwords(str_replace(array('-' , '_'), ' ', basename($newTmpl, '.php'))),
366
- 'OldTemplatePath' => $oldTmpl,
367
- 'NewTemplatePath' => $newTmpl,
368
- ));
369
- return 1;
370
- }
371
- }
372
- }
373
-
374
- protected function CheckStickyChange($oldStky, $newStky, $post){
375
- if($oldStky != $newStky){
376
- $event = $newStky ? 2049 : 2050;
377
- $this->plugin->alerts->Trigger($event, array(
378
- 'PostID' => $post->ID,
379
- 'PostType' => $post->post_type,
380
- 'PostTitle' => $post->post_title,
381
- ));
382
- return 1;
383
- }
384
- }
385
-
386
- protected function CheckModificationChange($oldpost, $newpost){
387
- $contentChanged = $oldpost->post_content != $newpost->post_content; // TODO what about excerpts?
388
-
389
- if($oldpost->post_modified != $newpost->post_modified){
390
- $event = 0;
391
- // @see http://codex.wordpress.org/Class_Reference/WP_Query#Status_Parameters
392
- switch($oldpost->post_status){ // TODO or should this be $newpost?
393
- case 'draft':
394
- if($contentChanged){
395
- $event = $this->GetEventTypeForPostType($newpost, 2068, 2069, 2070);
396
- }else{
397
- $event = $this->GetEventTypeForPostType($newpost, 2003, 2007, 2032);
398
- }
399
- break;
400
- case 'publish':
401
- if($contentChanged){
402
- $event = $this->GetEventTypeForPostType($newpost, 2065, 2066, 2067);
403
- }else{
404
- $event = $this->GetEventTypeForPostType($newpost, 2002, 2006, 2031);
405
- }
406
- break;
407
- }
408
- if($event){
409
- $this->plugin->alerts->Trigger($event, array(
410
- 'PostID' => $oldpost->ID,
411
- 'PostType' => $oldpost->post_type,
412
- 'PostTitle' => $oldpost->post_title,
413
- 'PostUrl' => get_permalink($oldpost->ID), // TODO or should this be $newpost?
414
- ));
415
- return 1;
416
- }
417
- }
418
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
419
 
420
- public function EventChangedCategoryParent() {
421
- if (empty($_POST)) return;
422
- if (!current_user_can("manage_categories")) return;
423
- if(isset($_POST['name'])) {
424
- $category = get_category($_POST['tag_ID']);
425
- if ( $category->parent != 0) {
426
- $oldParent = get_category($category->parent);
427
- $oldParentName = (empty($oldParent))? 'no parent' : $oldParent->name;
428
- } else {
429
- $oldParentName = 'no parent';
430
- }
431
- if(isset($_POST['parent'])) {
432
- $newParent = get_category($_POST['parent']);
433
- $newParentName = (empty($newParent))? 'no parent' : $newParent->name;
434
- }
435
- $this->plugin->alerts->Trigger(2052, array(
436
- 'CategoryName' => $category->name,
437
- 'OldParent' => $oldParentName,
438
- 'NewParent' => $newParentName,
439
- ));
440
- }
441
- }
 
 
 
 
 
442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  }
1
  <?php
2
 
3
+ class WSAL_Sensors_Content extends WSAL_AbstractSensor
4
+ {
5
 
6
+ public function HookEvents()
7
+ {
8
+ if (current_user_can("edit_posts")) {
9
+ add_action('admin_init', array($this, 'EventWordpressInit'));
10
+ }
11
+ add_action('transition_post_status', array($this, 'EventPostChanged'), 10, 3);
12
+ add_action('delete_post', array($this, 'EventPostDeleted'), 10, 1);
13
+ add_action('wp_trash_post', array($this, 'EventPostTrashed'), 10, 1);
14
+ add_action('untrash_post', array($this, 'EventPostUntrashed'));
15
+ add_action('edit_category', array($this, 'EventChangedCategoryParent'));
16
+ }
17
+
18
+ protected function GetEventTypeForPostType($post, $typePost, $typePage, $typeCustom)
19
+ {
20
+ switch ($post->post_type) {
21
+ case 'page':
22
+ return $typePage;
23
+ case 'post':
24
+ return $typePost;
25
+ default:
26
+ return $typeCustom;
27
+ }
28
+ }
29
+
30
+ protected $_OldPost = null;
31
+ protected $_OldLink = null;
32
+ protected $_OldCats = null;
33
+ protected $_OldTmpl = null;
34
+ protected $_OldStky = null;
35
+
36
+ public function EventWordpressInit()
37
+ {
38
+ // load old data, if applicable
39
+ $this->RetrieveOldData();
40
+ // check for category changes
41
+ $this->CheckCategoryCreation();
42
+ $this->CheckCategoryDeletion();
43
+ }
44
+
45
+ protected function RetrieveOldData()
46
+ {
47
  if (isset($_POST) && isset($_POST['post_ID'])
48
+ && !(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
49
+ && !(isset($_POST['action']) && $_POST['action'] == 'autosave')
50
+ ) {
51
+ $postID = intval($_POST['post_ID']);
52
+ $this->_OldPost = get_post($postID);
53
+ $this->_OldLink = get_permalink($postID);
54
+ $this->_OldTmpl = $this->GetPostTemplate($this->_OldPost);
55
+ $this->_OldCats = $this->GetPostCategories($this->_OldPost);
56
+ $this->_OldStky = in_array($postID, get_option('sticky_posts'));
57
+ }
58
+ }
59
+
60
+ protected function GetPostTemplate($post)
61
+ {
62
+ $id = $post->ID;
63
+ $template = get_page_template_slug($id);
64
+ $pagename = $post->post_name;
65
 
66
+ $templates = array();
67
+ if ($template && 0 === validate_file($template)) {
68
+ $templates[] = $template;
69
+ }
70
+ if ($pagename) {
71
+ $templates[] = "page-$pagename.php";
72
+ }
73
+ if ($id) {
74
+ $templates[] = "page-$id.php";
75
+ }
76
+ $templates[] = 'page.php';
77
 
78
+ return get_query_template('page', $templates);
79
+ }
80
 
81
+ protected function GetPostCategories($post)
82
+ {
83
+ return wp_get_post_categories($post->ID, array('fields' => 'names'));
84
+ }
85
 
86
+ public function EventPostChanged($newStatus, $oldStatus, $post)
87
+ {
88
+ // ignorable states
89
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
90
+ return;
91
+ }
92
+ if (empty($post->post_type)) {
93
+ return;
94
+ }
95
+ if ($post->post_type == 'revision') {
96
+ return;
97
+ }
98
+
99
+ $original = isset($_POST['original_post_status']) ? $_POST['original_post_status'] : '';
100
+
101
+ WSAL_Sensors_Request::SetVars(array(
102
+ '$newStatus' => $newStatus,
103
+ '$oldStatus' => $oldStatus,
104
+ '$original' => $original,
105
+ ));
106
  // run checks
107
+ if ($this->_OldPost) {
108
+ if ($oldStatus == 'auto-draft' || $original == 'auto-draft') {
109
+ // Handle create post events
110
+ $this->CheckPostCreation($this->_OldPost, $post);
111
+
112
+ } else {
113
+ // Handle update post events
114
+ $changes = 0
115
+ + $this->CheckDateChange($this->_OldPost, $post)
116
+ + $this->CheckAuthorChange($this->_OldPost, $post)
117
+ + $this->CheckStatusChange($this->_OldPost, $post)
118
+ + $this->CheckParentChange($this->_OldPost, $post)
119
+ + $this->CheckStickyChange($this->_OldStky, isset($_REQUEST['sticky']), $post)
120
+ + $this->CheckVisibilityChange($this->_OldPost, $post, $oldStatus, $newStatus)
121
+ + $this->CheckTemplateChange($this->_OldTmpl, $this->GetPostTemplate($post), $post)
122
+ + $this->CheckCategoriesChange($this->_OldCats, $this->GetPostCategories($post), $post)
123
+ ;
124
+ if (!$changes) {
125
+ $changes = $this->CheckPermalinkChange($this->_OldLink, get_permalink($post->ID), $post);
126
+ }
127
+ if (!$changes) {
128
+ $changes = $this->CheckModificationChange($this->_OldPost, $post);
129
+ }
130
+
131
+ }
132
+ }
133
+ }
134
+
135
+ protected function CheckPostCreation($oldPost, $newPost)
136
+ {
137
+ $event = 0;
138
+ switch ($newPost->post_status) {
139
+ case 'publish':
140
+ $event = $this->GetEventTypeForPostType($oldPost, 2001, 2005, 2030);
141
+ break;
142
+ case 'draft':
143
+ $event = $this->GetEventTypeForPostType($oldPost, 2000, 2004, 2029);
144
+ break;
145
+ }
146
+ if ($event) {
147
+ $this->plugin->alerts->Trigger($event, array(
148
+ 'PostID' => $newPost->ID,
149
+ 'PostType' => $newPost->post_type,
150
+ 'PostTitle' => $newPost->post_title,
151
+ 'PostUrl' => get_permalink($newPost->ID),
152
+ ));
153
+ }
154
+ }
155
+
156
+ protected function CheckCategoryCreation()
157
+ {
158
+ if (empty($_POST)) {
159
+ return;
160
+ }
161
+ $categoryName = '';
162
+ if (!empty($_POST['screen']) && !empty($_POST['tag-name']) &&
163
+ $_POST['screen'] == 'edit-category' &&
164
+ $_POST['taxonomy'] == 'category' &&
165
+ $_POST['action'] == 'add-tag') {
166
+ $categoryName = $_POST['tag-name'];
167
+ } elseif (!empty($_POST['newcategory']) && $_POST['action'] == 'add-category') {
168
+ $categoryName = $_POST['newcategory'];
169
+ }
170
+
171
+ if ($categoryName) {
172
+ $this->plugin->alerts->Trigger(2023, array(
173
+ 'CategoryName' => $categoryName,
174
+ ));
175
+ }
176
+ }
177
 
178
+ protected function CheckCategoryDeletion()
179
+ {
180
+ if (empty($_POST)) {
181
+ return;
182
+ }
183
+ $action = !empty($_POST['action']) ? $_POST['action']
184
+ : (!empty($_POST['action2']) ? $_POST['action2'] : '');
185
+ if (!$action) {
186
+ return;
187
+ }
188
 
189
+ $categoryIds = array();
190
 
191
+ if (isset($_POST['taxonomy'])) {
192
+ if ($action == 'delete' && $_POST['taxonomy'] == 'category' && !empty($_POST['delete_tags'])) {
193
+ // bulk delete
194
+ $categoryIds[] = $_POST['delete_tags'];
195
+ } elseif ($action == 'delete-tag' && $_POST['taxonomy'] == 'category' && !empty($_POST['tag_ID'])) {
196
+ // single delete
197
+ $categoryIds[] = $_POST['tag_ID'];
198
+ }
199
+ }
200
 
201
+ foreach ($categoryIds as $categoryID) {
202
+ $category = get_category($categoryID);
203
+ $this->plugin->alerts->Trigger(2024, array(
204
+ 'CategoryID' => $categoryID,
205
+ 'CategoryName' => $category->cat_name,
206
+ ));
207
+ }
208
+ }
209
+
210
+ public function EventPostDeleted($post_id)
211
+ {
212
+ $post = get_post($post_id);
213
+ if (!in_array($post->post_type, array('attachment', 'revision'))) { // ignore attachments and revisions
214
+ $event = $this->GetEventTypeForPostType($post, 2008, 2009, 2033);
215
+ // check WordPress backend operations
216
+ if ($this->CheckAutoDraft($event, $post->post_title)) {
217
+ return;
218
+ }
219
+ $this->plugin->alerts->Trigger($event, array(
220
+ 'PostID' => $post->ID,
221
+ 'PostType' => $post->post_type,
222
+ 'PostTitle' => $post->post_title,
223
+ ));
224
+ }
225
+ }
226
+
227
+ public function EventPostTrashed($post_id)
228
+ {
229
+ $post = get_post($post_id);
230
+ $event = $this->GetEventTypeForPostType($post, 2012, 2013, 2034);
231
+ $this->plugin->alerts->Trigger($event, array(
232
+ 'PostID' => $post->ID,
233
+ 'PostType' => $post->post_type,
234
+ 'PostTitle' => $post->post_title,
235
+ ));
236
+ }
237
+
238
+ public function EventPostUntrashed($post_id)
239
+ {
240
+ $post = get_post($post_id);
241
+ $event = $this->GetEventTypeForPostType($post, 2014, 2015, 2035);
242
+ $this->plugin->alerts->Trigger($event, array(
243
+ 'PostID' => $post->ID,
244
+ 'PostType' => $post->post_type,
245
+ 'PostTitle' => $post->post_title,
246
+ ));
247
+ }
248
+
249
+ protected function CheckDateChange($oldpost, $newpost)
250
+ {
251
  $from = strtotime($oldpost->post_date);
252
  $to = strtotime($newpost->post_date);
253
+ if ($oldpost->post_status == 'draft') {
254
+ return;
255
+ }
256
+ if ($from != $to) {
257
+ $event = $this->GetEventTypeForPostType($oldpost, 2027, 2028, 2041);
258
+ $this->plugin->alerts->Trigger($event, array(
259
+ 'PostID' => $oldpost->ID,
260
+ 'PostType' => $oldpost->post_type,
261
+ 'PostTitle' => $oldpost->post_title,
262
+ 'OldDate' => $oldpost->post_date,
263
+ 'NewDate' => $newpost->post_date,
264
+ ));
265
+ return 1;
266
+ }
267
+ }
268
+
269
+ protected function CheckCategoriesChange($oldCats, $newCats, $post)
270
+ {
271
+ $oldCats = implode(', ', $oldCats);
272
+ $newCats = implode(', ', $newCats);
273
+ if ($oldCats != $newCats) {
274
+ $event = $this->GetEventTypeForPostType($post, 2016, 0, 2036);
275
+ if ($event) {
276
+ $this->plugin->alerts->Trigger($event, array(
277
+ 'PostID' => $post->ID,
278
+ 'PostType' => $post->post_type,
279
+ 'PostTitle' => $post->post_title,
280
+ 'OldCategories' => $oldCats ? $oldCats : 'no categories',
281
+ 'NewCategories' => $newCats ? $newCats : 'no categories',
282
+ ));
283
+ return 1;
284
+ }
285
+ }
286
+ }
287
+
288
+ protected function CheckAuthorChange($oldpost, $newpost)
289
+ {
290
+ if ($oldpost->post_author != $newpost->post_author) {
291
+ $event = $this->GetEventTypeForPostType($oldpost, 2019, 2020, 2038);
292
+ $this->plugin->alerts->Trigger($event, array(
293
+ 'PostID' => $oldpost->ID,
294
+ 'PostType' => $oldpost->post_type,
295
+ 'PostTitle' => $oldpost->post_title,
296
+ 'OldAuthor' => get_userdata($oldpost->post_author)->user_login,
297
+ 'NewAuthor' => get_userdata($newpost->post_author)->user_login,
298
+ ));
299
+ return 1;
300
+ }
301
+ }
302
+
303
+ protected function CheckStatusChange($oldpost, $newpost)
304
+ {
305
+ if ($oldpost->post_status != $newpost->post_status) {
306
+ if (isset($_REQUEST['publish'])) {
307
+ // special case (publishing a post)
308
+ $event = $this->GetEventTypeForPostType($oldpost, 2001, 2005, 2030);
309
+ $this->plugin->alerts->Trigger($event, array(
310
+ 'PostID' => $newpost->ID,
311
+ 'PostType' => $newpost->post_type,
312
+ 'PostTitle' => $newpost->post_title,
313
+ 'PostUrl' => get_permalink($newpost->ID),
314
+ ));
315
+ } else {
316
+ $event = $this->GetEventTypeForPostType($oldpost, 2021, 2022, 2039);
317
+ $this->plugin->alerts->Trigger($event, array(
318
+ 'PostID' => $oldpost->ID,
319
+ 'PostType' => $oldpost->post_type,
320
+ 'PostTitle' => $oldpost->post_title,
321
+ 'OldStatus' => $oldpost->post_status,
322
+ 'NewStatus' => $newpost->post_status,
323
+ ));
324
+ }
325
+ return 1;
326
+ }
327
+ }
328
+
329
+ protected function CheckParentChange($oldpost, $newpost)
330
+ {
331
+ if ($oldpost->post_parent != $newpost->post_parent) {
332
+ $event = $this->GetEventTypeForPostType($oldpost, 0, 2047, 0);
333
+ if ($event) {
334
+ $this->plugin->alerts->Trigger($event, array(
335
+ 'PostID' => $oldpost->ID,
336
+ 'PostType' => $oldpost->post_type,
337
+ 'PostTitle' => $oldpost->post_title,
338
+ 'OldParent' => $oldpost->post_parent,
339
+ 'NewParent' => $newpost->post_parent,
340
+ 'OldParentName' => $oldpost->post_parent ? get_the_title($oldpost->post_parent) : 'no parent',
341
+ 'NewParentName' => $newpost->post_parent ? get_the_title($newpost->post_parent) : 'no parent',
342
+ ));
343
+ return 1;
344
+ }
345
+ }
346
+ }
347
+
348
+ protected function CheckPermalinkChange($oldLink, $newLink, $post)
349
+ {
350
+ if ($oldLink != $newLink) {
351
+ $event = $this->GetEventTypeForPostType($post, 2017, 2018, 2037);
352
+ $this->plugin->alerts->Trigger($event, array(
353
+ 'PostID' => $post->ID,
354
+ 'PostType' => $post->post_type,
355
+ 'PostTitle' => $post->post_title,
356
+ 'OldUrl' => $oldLink,
357
+ 'NewUrl' => $newLink,
358
+ ));
359
+ return 1;
360
+ }
361
+ }
362
+
363
+ protected function CheckVisibilityChange($oldpost, $newpost, $oldStatus, $newStatus)
364
+ {
365
+ if ($oldStatus == 'draft' || $newStatus == 'draft') {
366
+ return;
367
+ }
368
+
369
+ $oldVisibility = '';
370
+ $newVisibility = '';
371
+
372
+ if ($oldpost->post_password) {
373
+ $oldVisibility = __('Password Protected', 'wp-security-audit-log');
374
+ } elseif ($oldStatus == 'publish') {
375
+ $oldVisibility = __('Public', 'wp-security-audit-log');
376
+ } elseif ($oldStatus == 'private') {
377
+ $oldVisibility = __('Private', 'wp-security-audit-log');
378
+ }
379
+
380
+ if ($newpost->post_password) {
381
+ $newVisibility = __('Password Protected', 'wp-security-audit-log');
382
+ } elseif ($newStatus == 'publish') {
383
+ $newVisibility = __('Public', 'wp-security-audit-log');
384
+ } elseif ($newStatus == 'private') {
385
+ $newVisibility = __('Private', 'wp-security-audit-log');
386
+ }
387
+
388
+ if ($oldVisibility && $newVisibility && ($oldVisibility != $newVisibility)) {
389
+ $event = $this->GetEventTypeForPostType($oldpost, 2025, 2026, 2040);
390
+ $this->plugin->alerts->Trigger($event, array(
391
+ 'PostID' => $oldpost->ID,
392
+ 'PostType' => $oldpost->post_type,
393
+ 'PostTitle' => $oldpost->post_title,
394
+ 'OldVisibility' => $oldVisibility,
395
+ 'NewVisibility' => $newVisibility,
396
+ ));
397
+ return 1;
398
+ }
399
+ }
400
+
401
+ protected function CheckTemplateChange($oldTmpl, $newTmpl, $post)
402
+ {
403
+ if ($oldTmpl != $newTmpl) {
404
+ $event = $this->GetEventTypeForPostType($post, 0, 2048, 0);
405
+ if ($event) {
406
+ $this->plugin->alerts->Trigger($event, array(
407
+ 'PostID' => $post->ID,
408
+ 'PostType' => $post->post_type,
409
+ 'PostTitle' => $post->post_title,
410
+ 'OldTemplate' => ucwords(str_replace(array('-' , '_'), ' ', basename($oldTmpl, '.php'))),
411
+ 'NewTemplate' => ucwords(str_replace(array('-' , '_'), ' ', basename($newTmpl, '.php'))),
412
+ 'OldTemplatePath' => $oldTmpl,
413
+ 'NewTemplatePath' => $newTmpl,
414
+ ));
415
+ return 1;
416
+ }
417
+ }
418
+ }
419
+
420
+ protected function CheckStickyChange($oldStky, $newStky, $post)
421
+ {
422
+ if ($oldStky != $newStky) {
423
+ $event = $newStky ? 2049 : 2050;
424
+ $this->plugin->alerts->Trigger($event, array(
425
+ 'PostID' => $post->ID,
426
+ 'PostType' => $post->post_type,
427
+ 'PostTitle' => $post->post_title,
428
+ ));
429
+ return 1;
430
+ }
431
+ }
432
+
433
+ protected function CheckModificationChange($oldpost, $newpost)
434
+ {
435
+ $contentChanged = $oldpost->post_content != $newpost->post_content; // TODO what about excerpts?
436
+
437
+ if ($oldpost->post_modified != $newpost->post_modified) {
438
+ $event = 0;
439
+ // @see http://codex.wordpress.org/Class_Reference/WP_Query#Status_Parameters
440
+ switch ($oldpost->post_status) { // TODO or should this be $newpost?
441
+ case 'draft':
442
+ if ($contentChanged) {
443
+ $event = $this->GetEventTypeForPostType($newpost, 2068, 2069, 2070);
444
+ } else {
445
+ $event = $this->GetEventTypeForPostType($newpost, 2003, 2007, 2032);
446
+ }
447
+ break;
448
+ case 'publish':
449
+ if ($contentChanged) {
450
+ $event = $this->GetEventTypeForPostType($newpost, 2065, 2066, 2067);
451
+ } else {
452
+ $event = $this->GetEventTypeForPostType($newpost, 2002, 2006, 2031);
453
+ }
454
+ break;
455
+ }
456
+ if ($event) {
457
+ $this->plugin->alerts->Trigger($event, array(
458
+ 'PostID' => $oldpost->ID,
459
+ 'PostType' => $oldpost->post_type,
460
+ 'PostTitle' => $oldpost->post_title,
461
+ 'PostUrl' => get_permalink($oldpost->ID), // TODO or should this be $newpost?
462
+ ));
463
+ return 1;
464
+ }
465
+ }
466
+ }
467
 
468
+ public function EventChangedCategoryParent()
469
+ {
470
+ if (empty($_POST)) {
471
+ return;
472
+ }
473
+ if (!current_user_can("manage_categories")) {
474
+ return;
475
+ }
476
+ if (isset($_POST['name'])) {
477
+ $category = get_category($_POST['tag_ID']);
478
+ if ($category->parent != 0) {
479
+ $oldParent = get_category($category->parent);
480
+ $oldParentName = (empty($oldParent))? 'no parent' : $oldParent->name;
481
+ } else {
482
+ $oldParentName = 'no parent';
483
+ }
484
+ if (isset($_POST['parent'])) {
485
+ $newParent = get_category($_POST['parent']);
486
+ $newParentName = (empty($newParent))? 'no parent' : $newParent->name;
487
+ }
488
+ $this->plugin->alerts->Trigger(2052, array(
489
+ 'CategoryName' => $category->name,
490
+ 'OldParent' => $oldParentName,
491
+ 'NewParent' => $newParentName,
492
+ ));
493
+ }
494
+ }
495
 
496
+ private function CheckAutoDraft($code, $title)
497
+ {
498
+ if ($code == 2008 && $title == "auto-draft") {
499
+ // to do check setting else return false
500
+ if ($this->plugin->settings->IsWPBackend() == 1) {
501
+ return true;
502
+ } else {
503
+ return false;
504
+ }
505
+ } else {
506
+ return false;
507
+ }
508
+ }
509
  }
classes/Sensors/LogInOut.php CHANGED
@@ -2,166 +2,169 @@
2
 
3
  class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
4
 
5
- public function HookEvents() {
6
- add_action('wp_login', array($this, 'EventLogin'), 10, 2);
7
- add_action('wp_logout', array($this, 'EventLogout'));
8
- add_action('wp_login_failed', array($this, 'EventLoginFailure'));
9
- add_action('clear_auth_cookie', array($this, 'GetCurrentUser'), 10);
10
- }
11
-
12
- protected $_current_user = null;
13
-
14
- public function GetCurrentUser(){
15
- $this->_current_user = wp_get_current_user();
16
- }
17
-
18
- public function EventLogin($user_login, $user){
19
- $userRoles = $this->plugin->settings->GetCurrentUserRoles($user->roles);
20
- if ( $this->plugin->settings->IsLoginSuperAdmin($user_login) ) $userRoles[] = 'superadmin';
21
- $this->plugin->alerts->Trigger(1000, array(
22
- 'Username' => $user_login,
23
- 'CurrentUserRoles' => $userRoles,
24
- ), true);
25
- }
26
-
27
- public function EventLogout(){
28
- if($this->_current_user->ID != 0){
29
- $this->plugin->alerts->Trigger(1001, array(
30
- 'CurrentUserID' => $this->_current_user->ID,
31
- 'CurrentUserRoles' => $this->plugin->settings->GetCurrentUserRoles($this->_current_user->roles),
32
- ), true);
33
- }
34
- }
 
 
 
35
 
36
- /**
37
- * @return boolean Whether we are running on multisite or not.
38
- */
39
- public function IsMultisite(){
40
- return function_exists('is_multisite') && is_multisite();
41
- }
42
-
43
- const TRANSIENT_FAILEDLOGINS = 'wsal-failedlogins-known';
44
- const TRANSIENT_FAILEDLOGINS_UNKNOWN = 'wsal-failedlogins-unknown';
45
-
46
- protected function GetLoginFailureLogLimit(){
47
- return 10;
48
- }
49
-
50
- protected function GetLoginFailureExpiration(){
51
- return 12 * 60 * 60;
52
- }
53
-
54
- protected function IsPastLoginFailureLimit($ip, $site_id, $user){
55
- $get_fn = $this->IsMultisite() ? 'get_site_transient' : 'get_transient';
56
- if($user) {
57
- $dataKnown = $get_fn(self::TRANSIENT_FAILEDLOGINS);
58
- return ($dataKnown !== false) && isset($dataKnown[$site_id.":".$user->ID.":".$ip]) && ($dataKnown[$site_id.":".$user->ID.":".$ip] > $this->GetLoginFailureLogLimit());
59
- } else {
60
- $dataUnknown = $get_fn(self::TRANSIENT_FAILEDLOGINS_UNKNOWN);
61
- return ($dataUnknown !== false) && isset($dataUnknown[$site_id.":".$ip]) && ($dataUnknown[$site_id.":".$ip] > $this->GetLoginFailureLogLimit());
62
- }
63
- }
64
-
65
- protected function IncrementLoginFailure($ip, $site_id, $user){
66
- $get_fn = $this->IsMultisite() ? 'get_site_transient' : 'get_transient';
67
- $set_fn = $this->IsMultisite() ? 'set_site_transient' : 'set_transient';
68
- if($user) {
69
- $dataKnown = $get_fn(self::TRANSIENT_FAILEDLOGINS);
70
- if(!$dataKnown)$dataKnown = array();
71
- if(!isset($dataKnown[$site_id.":".$user->ID.":".$ip]))$dataKnown[$site_id.":".$user->ID.":".$ip] = 1;
72
- $dataKnown[$site_id.":".$user->ID.":".$ip]++;
73
- $set_fn(self::TRANSIENT_FAILEDLOGINS, $dataKnown, $this->GetLoginFailureExpiration());
74
- } else {
75
- $dataUnknown = $get_fn(self::TRANSIENT_FAILEDLOGINS_UNKNOWN);
76
- if(!$dataUnknown)$dataUnknown = array();
77
- if(!isset($dataUnknown[$site_id.":".$ip]))$dataUnknown[$site_id.":".$ip] = 1;
78
- $dataUnknown[$site_id.":".$ip]++;
79
- $set_fn(self::TRANSIENT_FAILEDLOGINS_UNKNOWN, $dataUnknown, $this->GetLoginFailureExpiration());
80
- }
81
- }
82
-
83
- public function EventLoginFailure($username){
84
-
85
- list($y, $m, $d) = explode('-', date('Y-m-d'));
86
-
87
- $ip = $this->plugin->settings->GetMainClientIP();
88
-
89
- $username = $_POST["log"];
90
- $newAlertCode = 1003;
91
- $user = get_user_by('login', $username);
92
- $site_id = (function_exists('get_current_blog_id') ? get_current_blog_id() : 0);
93
- if ($user) {
94
- $newAlertCode = 1002;
95
- $userRoles = $this->plugin->settings->GetCurrentUserRoles($user->roles);
96
- if ( $this->plugin->settings->IsLoginSuperAdmin($username) ) $userRoles[] = 'superadmin';
97
- }
98
 
99
- if($this->IsPastLoginFailureLimit($ip, $site_id, $user))return;
100
 
101
- $objOcc = new WSAL_Models_Occurrence();
102
-
103
- if ($newAlertCode == 1002) {
104
- if (!$this->plugin->alerts->CheckEnableUserRoles($username, $userRoles))return;
105
- $occ = $objOcc->CheckKnownUsers(
106
- array(
107
- $ip,
108
- $username,
109
- 1002,
110
- $site_id,
111
- mktime(0, 0, 0, $m, $d, $y),
112
- mktime(0, 0, 0, $m, $d + 1, $y) - 1
113
- )
114
- );
115
- $occ = count($occ) ? $occ[0] : null;
116
-
117
- if(!empty($occ)){
118
- // update existing record exists user
119
- $this->IncrementLoginFailure($ip, $site_id, $user);
120
- $new = $occ->GetMetaValue('Attempts', 0) + 1;
121
-
122
- if($new > $this->GetLoginFailureLogLimit())
123
- $new = $this->GetLoginFailureLogLimit() . '+';
124
-
125
- $occ->UpdateMetaValue('Attempts', $new);
126
- $occ->UpdateMetaValue('Username', $username);
127
- //$occ->SetMetaValue('CurrentUserRoles', $userRoles);
128
- $occ->created_on = null;
129
- $occ->Save();
130
- } else {
131
- // create a new record exists user
132
- $this->plugin->alerts->Trigger($newAlertCode, array(
133
- 'Attempts' => 1,
134
- 'Username' => $username,
135
- 'CurrentUserRoles' => $userRoles
136
- ));
137
- }
138
- } else {
139
- $occUnknown = $objOcc->CheckUnKnownUsers(
140
- array(
141
- $ip,
142
- 1003,
143
- $site_id,
144
- mktime(0, 0, 0, $m, $d, $y),
145
- mktime(0, 0, 0, $m, $d + 1, $y) - 1
146
- )
147
- );
148
-
149
- $occUnknown = count($occUnknown) ? $occUnknown[0] : null;
150
- if(!empty($occUnknown)) {
151
- // update existing record not exists user
152
- $this->IncrementLoginFailure($ip, $site_id, false);
153
- $new = $occUnknown->GetMetaValue('Attempts', 0) + 1;
154
-
155
- if($new > $this->GetLoginFailureLogLimit())
156
- $new = $this->GetLoginFailureLogLimit() . '+';
157
-
158
- $occUnknown->UpdateMetaValue('Attempts', $new);
159
- $occUnknown->created_on = null;
160
- $occUnknown->Save();
161
- } else {
162
- // create a new record not exists user
163
- $this->plugin->alerts->Trigger($newAlertCode, array('Attempts' => 1));
164
- }
165
- }
166
- }
167
  }
2
 
3
  class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
4
 
5
+ public function HookEvents() {
6
+ add_action('wp_login', array($this, 'EventLogin'), 10, 2);
7
+ add_action('wp_logout', array($this, 'EventLogout'));
8
+ add_action('wp_login_failed', array($this, 'EventLoginFailure'));
9
+ add_action('clear_auth_cookie', array($this, 'GetCurrentUser'), 10);
10
+ }
11
+
12
+ protected $_current_user = null;
13
+
14
+ public function GetCurrentUser(){
15
+ $this->_current_user = wp_get_current_user();
16
+ }
17
+
18
+ public function EventLogin($user_login, $user = null) {
19
+ if (empty($user)) {
20
+ $user = get_user_by('login', $user_login);
21
+ }
22
+ $userRoles = $this->plugin->settings->GetCurrentUserRoles($user->roles);
23
+ if ( $this->plugin->settings->IsLoginSuperAdmin($user_login) ) $userRoles[] = 'superadmin';
24
+ $this->plugin->alerts->Trigger(1000, array(
25
+ 'Username' => $user_login,
26
+ 'CurrentUserRoles' => $userRoles,
27
+ ), true);
28
+ }
29
+
30
+ public function EventLogout(){
31
+ if($this->_current_user->ID != 0){
32
+ $this->plugin->alerts->Trigger(1001, array(
33
+ 'CurrentUserID' => $this->_current_user->ID,
34
+ 'CurrentUserRoles' => $this->plugin->settings->GetCurrentUserRoles($this->_current_user->roles),
35
+ ), true);
36
+ }
37
+ }
38
 
39
+ /**
40
+ * @return boolean Whether we are running on multisite or not.
41
+ */
42
+ public function IsMultisite(){
43
+ return function_exists('is_multisite') && is_multisite();
44
+ }
45
+
46
+ const TRANSIENT_FAILEDLOGINS = 'wsal-failedlogins-known';
47
+ const TRANSIENT_FAILEDLOGINS_UNKNOWN = 'wsal-failedlogins-unknown';
48
+
49
+ protected function GetLoginFailureLogLimit(){
50
+ return 10;
51
+ }
52
+
53
+ protected function GetLoginFailureExpiration(){
54
+ return 12 * 60 * 60;
55
+ }
56
+
57
+ protected function IsPastLoginFailureLimit($ip, $site_id, $user){
58
+ $get_fn = $this->IsMultisite() ? 'get_site_transient' : 'get_transient';
59
+ if($user) {
60
+ $dataKnown = $get_fn(self::TRANSIENT_FAILEDLOGINS);
61
+ return ($dataKnown !== false) && isset($dataKnown[$site_id.":".$user->ID.":".$ip]) && ($dataKnown[$site_id.":".$user->ID.":".$ip] > $this->GetLoginFailureLogLimit());
62
+ } else {
63
+ $dataUnknown = $get_fn(self::TRANSIENT_FAILEDLOGINS_UNKNOWN);
64
+ return ($dataUnknown !== false) && isset($dataUnknown[$site_id.":".$ip]) && ($dataUnknown[$site_id.":".$ip] > $this->GetLoginFailureLogLimit());
65
+ }
66
+ }
67
+
68
+ protected function IncrementLoginFailure($ip, $site_id, $user){
69
+ $get_fn = $this->IsMultisite() ? 'get_site_transient' : 'get_transient';
70
+ $set_fn = $this->IsMultisite() ? 'set_site_transient' : 'set_transient';
71
+ if($user) {
72
+ $dataKnown = $get_fn(self::TRANSIENT_FAILEDLOGINS);
73
+ if(!$dataKnown)$dataKnown = array();
74
+ if(!isset($dataKnown[$site_id.":".$user->ID.":".$ip]))$dataKnown[$site_id.":".$user->ID.":".$ip] = 1;
75
+ $dataKnown[$site_id.":".$user->ID.":".$ip]++;
76
+ $set_fn(self::TRANSIENT_FAILEDLOGINS, $dataKnown, $this->GetLoginFailureExpiration());
77
+ } else {
78
+ $dataUnknown = $get_fn(self::TRANSIENT_FAILEDLOGINS_UNKNOWN);
79
+ if(!$dataUnknown)$dataUnknown = array();
80
+ if(!isset($dataUnknown[$site_id.":".$ip]))$dataUnknown[$site_id.":".$ip] = 1;
81
+ $dataUnknown[$site_id.":".$ip]++;
82
+ $set_fn(self::TRANSIENT_FAILEDLOGINS_UNKNOWN, $dataUnknown, $this->GetLoginFailureExpiration());
83
+ }
84
+ }
85
+
86
+ public function EventLoginFailure($username){
87
+
88
+ list($y, $m, $d) = explode('-', date('Y-m-d'));
89
+
90
+ $ip = $this->plugin->settings->GetMainClientIP();
91
+
92
+ $username = $_POST["log"];
93
+ $newAlertCode = 1003;
94
+ $user = get_user_by('login', $username);
95
+ $site_id = (function_exists('get_current_blog_id') ? get_current_blog_id() : 0);
96
+ if ($user) {
97
+ $newAlertCode = 1002;
98
+ $userRoles = $this->plugin->settings->GetCurrentUserRoles($user->roles);
99
+ if ( $this->plugin->settings->IsLoginSuperAdmin($username) ) $userRoles[] = 'superadmin';
100
+ }
101
 
102
+ if($this->IsPastLoginFailureLimit($ip, $site_id, $user))return;
103
 
104
+ $objOcc = new WSAL_Models_Occurrence();
105
+
106
+ if ($newAlertCode == 1002) {
107
+ if (!$this->plugin->alerts->CheckEnableUserRoles($username, $userRoles))return;
108
+ $occ = $objOcc->CheckKnownUsers(
109
+ array(
110
+ $ip,
111
+ $username,
112
+ 1002,
113
+ $site_id,
114
+ mktime(0, 0, 0, $m, $d, $y),
115
+ mktime(0, 0, 0, $m, $d + 1, $y) - 1
116
+ )
117
+ );
118
+ $occ = count($occ) ? $occ[0] : null;
119
+
120
+ if(!empty($occ)){
121
+ // update existing record exists user
122
+ $this->IncrementLoginFailure($ip, $site_id, $user);
123
+ $new = $occ->GetMetaValue('Attempts', 0) + 1;
124
+
125
+ if($new > $this->GetLoginFailureLogLimit())
126
+ $new = $this->GetLoginFailureLogLimit() . '+';
127
+
128
+ $occ->UpdateMetaValue('Attempts', $new);
129
+ $occ->UpdateMetaValue('Username', $username);
130
+ //$occ->SetMetaValue('CurrentUserRoles', $userRoles);
131
+ $occ->created_on = null;
132
+ $occ->Save();
133
+ } else {
134
+ // create a new record exists user
135
+ $this->plugin->alerts->Trigger($newAlertCode, array(
136
+ 'Attempts' => 1,
137
+ 'Username' => $username,
138
+ 'CurrentUserRoles' => $userRoles
139
+ ));
140
+ }
141
+ } else {
142
+ $occUnknown = $objOcc->CheckUnKnownUsers(
143
+ array(
144
+ $ip,
145
+ 1003,
146
+ $site_id,
147
+ mktime(0, 0, 0, $m, $d, $y),
148
+ mktime(0, 0, 0, $m, $d + 1, $y) - 1
149
+ )
150
+ );
151
+
152
+ $occUnknown = count($occUnknown) ? $occUnknown[0] : null;
153
+ if(!empty($occUnknown)) {
154
+ // update existing record not exists user
155
+ $this->IncrementLoginFailure($ip, $site_id, false);
156
+ $new = $occUnknown->GetMetaValue('Attempts', 0) + 1;
157
+
158
+ if($new > $this->GetLoginFailureLogLimit())
159
+ $new = $this->GetLoginFailureLogLimit() . '+';
160
+
161
+ $occUnknown->UpdateMetaValue('Attempts', $new);
162
+ $occUnknown->created_on = null;
163
+ $occUnknown->Save();
164
+ } else {
165
+ // create a new record not exists user
166
+ $this->plugin->alerts->Trigger($newAlertCode, array('Attempts' => 1));
167
+ }
168
+ }
169
+ }
170
  }
classes/Sensors/MetaData.php CHANGED
@@ -2,204 +2,208 @@
2
 
3
  class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
4
 
5
- public function HookEvents() {
6
- add_action('add_post_meta', array($this, 'EventPostMetaCreated'), 10, 3);
7
- add_action('update_post_meta', array($this, 'EventPostMetaUpdating'), 10, 3);
8
- add_action('updated_post_meta', array($this, 'EventPostMetaUpdated'), 10, 4);
9
- add_action('deleted_post_meta', array($this, 'EventPostMetaDeleted'), 10, 3);
10
- }
11
-
12
- protected $old_meta = array();
13
-
14
- protected function CanLogPostMeta($object_id, $meta_key)
15
- {
16
- //check if excluded meta key or starts with _
17
- if ( substr($meta_key, 0, 1) == '_' ) {
18
- return false;
19
- } else if( $this->IsExcludedCustomFields($meta_key) ) {
20
- return false;
21
- } else {
22
- return true;
23
- }
24
- }
25
 
26
- public function IsExcludedCustomFields($custom)
27
- {
28
- $customFields = $this->plugin->settings->GetExcludedMonitoringCustom();
29
- return (in_array($custom, $customFields)) ? true : false;
30
- }
31
-
32
- public function EventPostMetaCreated($object_id, $meta_key, $_meta_value){
33
- $post = get_post($object_id);
34
 
35
- if(!$this->CanLogPostMeta($object_id, $meta_key))return;
36
-
37
- switch($post->post_type){
38
- case 'page':
39
- $this->plugin->alerts->Trigger(2059, array(
40
- 'PostID' => $object_id,
41
- 'PostTitle' => $post->post_title,
42
- 'MetaKey' => $meta_key,
43
- 'MetaValue' => $_meta_value,
44
- 'MetaLink' => $meta_key,
45
- ));
46
- break;
47
- case 'post':
48
- $this->plugin->alerts->Trigger(2053, array(
49
- 'PostID' => $object_id,
50
- 'PostTitle' => $post->post_title,
51
- 'MetaKey' => $meta_key,
52
- 'MetaValue' => $_meta_value,
53
- 'MetaLink' => $meta_key,
54
- ));
55
- break;
56
- default:
57
- $this->plugin->alerts->Trigger(2056, array(
58
- 'PostID' => $object_id,
59
- 'PostTitle' => $post->post_title,
60
- 'PostType' => $post->post_type,
61
- 'MetaKey' => $meta_key,
62
- 'MetaValue' => $_meta_value,
63
- 'MetaLink' => $meta_key,
64
- ));
65
- break;
66
- }
67
- }
68
-
69
- public function EventPostMetaUpdating($meta_id, $object_id, $meta_key){
70
- static $meta_type = 'post';
71
- $this->old_meta[$meta_id] = (object)array(
72
- 'key' => ($meta = get_metadata_by_mid($meta_type, $meta_id)) ? $meta->meta_key : $meta_key,
73
- 'val' => get_metadata($meta_type, $object_id, $meta_key, true),
74
- );
75
- }
76
-
77
- public function EventPostMetaUpdated($meta_id, $object_id, $meta_key, $_meta_value){
78
- $post = get_post($object_id);
79
-
80
- if(!$this->CanLogPostMeta($object_id, $meta_key))return;
81
-
82
- if(isset($this->old_meta[$meta_id])){
83
-
84
- // check change in meta key
85
- if($this->old_meta[$meta_id]->key != $meta_key){
86
- switch($post->post_type){
87
- case 'page':
88
- $this->plugin->alerts->Trigger(2064, array(
89
- 'PostID' => $object_id,
90
- 'PostTitle' => $post->post_title,
91
- 'MetaID' => $meta_id,
92
- 'MetaKeyNew' => $meta_key,
93
- 'MetaKeyOld' => $this->old_meta[$meta_id]->key,
94
- 'MetaValue' => $_meta_value,
95
- 'MetaLink' => $meta_key,
96
- ));
97
- break;
98
- case 'post':
99
- $this->plugin->alerts->Trigger(2062, array(
100
- 'PostID' => $object_id,
101
- 'PostTitle' => $post->post_title,
102
- 'MetaID' => $meta_id,
103
- 'MetaKeyNew' => $meta_key,
104
- 'MetaKeyOld' => $this->old_meta[$meta_id]->key,
105
- 'MetaValue' => $_meta_value,
106
- 'MetaLink' => $meta_key,
107
- ));
108
- break;
109
- default:
110
- $this->plugin->alerts->Trigger(2063, array(
111
- 'PostID' => $object_id,
112
- 'PostTitle' => $post->post_title,
113
- 'PostType' => $post->post_type,
114
- 'MetaID' => $meta_id,
115
- 'MetaKeyNew' => $meta_key,
116
- 'MetaKeyOld' => $this->old_meta[$meta_id]->key,
117
- 'MetaValue' => $_meta_value,
118
- 'MetaLink' => $smeta_key,
119
- ));
120
- break;
121
- }
122
- }
123
- else
124
- // check change in meta value
125
- if($this->old_meta[$meta_id]->val != $_meta_value){
126
- switch($post->post_type){
127
- case 'page':
128
- $this->plugin->alerts->Trigger(2060, array(
129
- 'PostID' => $object_id,
130
- 'PostTitle' => $post->post_title,
131
- 'MetaID' => $meta_id,
132
- 'MetaKey' => $meta_key,
133
- 'MetaValueNew' => $_meta_value,
134
- 'MetaValueOld' => $this->old_meta[$meta_id]->val,
135
- 'MetaLink' => $meta_key,
136
- ));
137
- break;
138
- case 'post':
139
- $this->plugin->alerts->Trigger(2054, array(
140
- 'PostID' => $object_id,
141
- 'PostTitle' => $post->post_title,
142
- 'MetaID' => $meta_id,
143
- 'MetaKey' => $meta_key,
144
- 'MetaValueNew' => $_meta_value,
145
- 'MetaValueOld' => $this->old_meta[$meta_id]->val,
146
- 'MetaLink' => $meta_key,
147
- ));
148
- break;
149
- default:
150
- $this->plugin->alerts->Trigger(2057, array(
151
- 'PostID' => $object_id,
152
- 'PostTitle' => $post->post_title,
153
- 'PostType' => $post->post_type,
154
- 'MetaID' => $meta_id,
155
- 'MetaKey' => $meta_key,
156
- 'MetaValueNew' => $_meta_value,
157
- 'MetaValueOld' => $this->old_meta[$meta_id]->val,
158
- 'MetaLink' => $meta_key,
159
- ));
160
- break;
161
- }
162
- }
163
-
164
- // remove old meta update data
165
- unset($this->old_meta[$meta_id]);
166
- }
167
- }
168
-
169
- public function EventPostMetaDeleted($object_id, $meta_id, $meta_key){
170
- $post = get_post($object_id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
- if(!$this->CanLogPostMeta($object_id, $meta_key))return;
173
-
174
- switch($post->post_type){
175
- case 'page':
176
- $this->plugin->alerts->Trigger(2061, array(
177
- 'PostID' => $object_id,
178
- 'PostTitle' => $post->post_title,
179
- 'MetaID' => $meta_id,
180
- 'MetaKey' => $meta_key,
181
- 'MetaLink' => $meta_key,
182
- ));
183
- break;
184
- case 'post':
185
- $this->plugin->alerts->Trigger(2055, array(
186
- 'PostID' => $object_id,
187
- 'PostTitle' => $post->post_title,
188
- 'MetaID' => $meta_id,
189
- 'MetaKey' => $meta_key,
190
- 'MetaLink' => $meta_key,
191
- ));
192
- break;
193
- default:
194
- $this->plugin->alerts->Trigger(2058, array(
195
- 'PostID' => $object_id,
196
- 'PostTitle' => $post->post_title,
197
- 'PostType' => $post->post_type,
198
- 'MetaID' => $meta_id,
199
- 'MetaKey' => $meta_key,
200
- 'MetaLink' => $meta_key,
201
- ));
202
- break;
203
- }
204
- }
205
  }
2
 
3
  class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
4
 
5
+ public function HookEvents() {
6
+ add_action('add_post_meta', array($this, 'EventPostMetaCreated'), 10, 3);
7
+ add_action('update_post_meta', array($this, 'EventPostMetaUpdating'), 10, 3);
8
+ add_action('updated_post_meta', array($this, 'EventPostMetaUpdated'), 10, 4);
9
+ add_action('deleted_post_meta', array($this, 'EventPostMetaDeleted'), 10, 4);
10
+ }
11
+
12
+ protected $old_meta = array();
13
+
14
+ protected function CanLogPostMeta($object_id, $meta_key)
15
+ {
16
+ //check if excluded meta key or starts with _
17
+ if ( substr($meta_key, 0, 1) == '_' ) {
18
+ return false;
19
+ } else if ( $this->IsExcludedCustomFields($meta_key) ) {
20
+ return false;
21
+ } else {
22
+ return true;
23
+ }
24
+ }
25
 
26
+ public function IsExcludedCustomFields($custom)
27
+ {
28
+ $customFields = $this->plugin->settings->GetExcludedMonitoringCustom();
29
+ return (in_array($custom, $customFields)) ? true : false;
30
+ }
31
+
32
+ public function EventPostMetaCreated($object_id, $meta_key, $_meta_value) {
33
+ $post = get_post($object_id);
34
 
35
+ if(!$this->CanLogPostMeta($object_id, $meta_key))return;
36
+
37
+ switch($post->post_type){
38
+ case 'page':
39
+ $this->plugin->alerts->Trigger(2059, array(
40
+ 'PostID' => $object_id,
41
+ 'PostTitle' => $post->post_title,
42
+ 'MetaKey' => $meta_key,
43
+ 'MetaValue' => $_meta_value,
44
+ 'MetaLink' => $meta_key,
45
+ ));
46
+ break;
47
+ case 'post':
48
+ $this->plugin->alerts->Trigger(2053, array(
49
+ 'PostID' => $object_id,
50
+ 'PostTitle' => $post->post_title,
51
+ 'MetaKey' => $meta_key,
52
+ 'MetaValue' => $_meta_value,
53
+ 'MetaLink' => $meta_key,
54
+ ));
55
+ break;
56
+ default:
57
+ $this->plugin->alerts->Trigger(2056, array(
58
+ 'PostID' => $object_id,
59
+ 'PostTitle' => $post->post_title,
60
+ 'PostType' => $post->post_type,
61
+ 'MetaKey' => $meta_key,
62
+ 'MetaValue' => $_meta_value,
63
+ 'MetaLink' => $meta_key,
64
+ ));
65
+ break;
66
+ }
67
+ }
68
+
69
+ public function EventPostMetaUpdating($meta_id, $object_id, $meta_key){
70
+ static $meta_type = 'post';
71
+ $this->old_meta[$meta_id] = (object)array(
72
+ 'key' => ($meta = get_metadata_by_mid($meta_type, $meta_id)) ? $meta->meta_key : $meta_key,
73
+ 'val' => get_metadata($meta_type, $object_id, $meta_key, true),
74
+ );
75
+ }
76
+
77
+ public function EventPostMetaUpdated($meta_id, $object_id, $meta_key, $_meta_value){
78
+ $post = get_post($object_id);
79
+
80
+ if(!$this->CanLogPostMeta($object_id, $meta_key))return;
81
+
82
+ if(isset($this->old_meta[$meta_id])){
83
+
84
+ // check change in meta key
85
+ if($this->old_meta[$meta_id]->key != $meta_key){
86
+ switch($post->post_type){
87
+ case 'page':
88
+ $this->plugin->alerts->Trigger(2064, array(
89
+ 'PostID' => $object_id,
90
+ 'PostTitle' => $post->post_title,
91
+ 'MetaID' => $meta_id,
92
+ 'MetaKeyNew' => $meta_key,
93
+ 'MetaKeyOld' => $this->old_meta[$meta_id]->key,
94
+ 'MetaValue' => $_meta_value,
95
+ 'MetaLink' => $meta_key,
96
+ ));
97
+ break;
98
+ case 'post':
99
+ $this->plugin->alerts->Trigger(2062, array(
100
+ 'PostID' => $object_id,
101
+ 'PostTitle' => $post->post_title,
102
+ 'MetaID' => $meta_id,
103
+ 'MetaKeyNew' => $meta_key,
104
+ 'MetaKeyOld' => $this->old_meta[$meta_id]->key,
105
+ 'MetaValue' => $_meta_value,
106
+ 'MetaLink' => $meta_key,
107
+ ));
108
+ break;
109
+ default:
110
+ $this->plugin->alerts->Trigger(2063, array(
111
+ 'PostID' => $object_id,
112
+ 'PostTitle' => $post->post_title,
113
+ 'PostType' => $post->post_type,
114
+ 'MetaID' => $meta_id,
115
+ 'MetaKeyNew' => $meta_key,
116
+ 'MetaKeyOld' => $this->old_meta[$meta_id]->key,
117
+ 'MetaValue' => $_meta_value,
118
+ 'MetaLink' => $smeta_key,
119
+ ));
120
+ break;
121
+ }
122
+ }
123
+ else
124
+ // check change in meta value
125
+ if($this->old_meta[$meta_id]->val != $_meta_value){
126
+ switch($post->post_type){
127
+ case 'page':
128
+ $this->plugin->alerts->Trigger(2060, array(
129
+ 'PostID' => $object_id,
130
+ 'PostTitle' => $post->post_title,
131
+ 'MetaID' => $meta_id,
132
+ 'MetaKey' => $meta_key,
133
+ 'MetaValueNew' => $_meta_value,
134
+ 'MetaValueOld' => $this->old_meta[$meta_id]->val,
135
+ 'MetaLink' => $meta_key,
136
+ ));
137
+ break;
138
+ case 'post':
139
+ $this->plugin->alerts->Trigger(2054, array(
140
+ 'PostID' => $object_id,
141
+ 'PostTitle' => $post->post_title,
142
+ 'MetaID' => $meta_id,
143
+ 'MetaKey' => $meta_key,
144
+ 'MetaValueNew' => $_meta_value,
145
+ 'MetaValueOld' => $this->old_meta[$meta_id]->val,
146
+ 'MetaLink' => $meta_key,
147
+ ));
148
+ break;
149
+ default:
150
+ $this->plugin->alerts->Trigger(2057, array(
151
+ 'PostID' => $object_id,
152
+ 'PostTitle' => $post->post_title,
153
+ 'PostType' => $post->post_type,
154
+ 'MetaID' => $meta_id,
155
+ 'MetaKey' => $meta_key,
156
+ 'MetaValueNew' => $_meta_value,
157
+ 'MetaValueOld' => $this->old_meta[$meta_id]->val,
158
+ 'MetaLink' => $meta_key,
159
+ ));
160
+ break;
161
+ }
162
+ }
163
+
164
+ // remove old meta update data
165
+ unset($this->old_meta[$meta_id]);
166
+ }
167
+ }
168
+
169
+ public function EventPostMetaDeleted($meta_ids, $object_id, $meta_key, $_meta_value){
170
+ $post = get_post($object_id);
171
+
172
+ foreach($meta_ids as $meta_id){
173
+
174
+ if(!$this->CanLogPostMeta($object_id, $meta_key))continue;
175
+
176
+ switch($post->post_type){
177
+ case 'page':
178
+ $this->plugin->alerts->Trigger(2061, array(
179
+ 'PostID' => $object_id,
180
+ 'PostTitle' => $post->post_title,
181
+ 'MetaID' => $meta_id,
182
+ 'MetaKey' => $meta_key,
183
+ 'MetaValue' => $_meta_value,
184
+ ));
185
+ break;
186
+ case 'post':
187
+ $this->plugin->alerts->Trigger(2055, array(
188
+ 'PostID' => $object_id,
189
+ 'PostTitle' => $post->post_title,
190
+ 'MetaID' => $meta_id,
191
+ 'MetaKey' => $meta_key,
192
+ 'MetaValue' => $_meta_value,
193
+ ));
194
+ break;
195
+ default:
196
+ $this->plugin->alerts->Trigger(2058, array(
197
+ 'PostID' => $object_id,
198
+ 'PostTitle' => $post->post_title,
199
+ 'PostType' => $post->post_type,
200
+ 'MetaID' => $meta_id,
201
+ 'MetaKey' => $meta_key,
202
+ 'MetaValue' => $_meta_value,
203
+ ));
204
+ break;
205
+ }
206
+ }
207
+ }
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  }
classes/Sensors/Widgets.php CHANGED
@@ -2,29 +2,29 @@
2
 
3
  class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
4
 
5
- public function HookEvents() {
6
- if(current_user_can("edit_theme_options")) {
7
- add_action('admin_init', array($this, 'EventWidgetMove'));
8
- add_action('admin_init', array($this, 'EventWidgetPostMove'));
9
- }
10
- add_action('sidebar_admin_setup', array($this, 'EventWidgetActivity'));
11
- }
12
 
13
- protected $_WidgetMoveData = null;
14
-
15
- public function EventWidgetMove(){
16
  if(isset($_POST) && !empty($_POST['sidebars']))
17
- {
18
  $crtSidebars = $_POST['sidebars'];
19
  $sidebars = array();
20
  foreach ( $crtSidebars as $key => $val )
21
- {
22
  $sb = array();
23
  if ( !empty($val) )
24
- {
25
  $val = explode(',', $val);
26
  foreach ( $val as $k => $v )
27
- {
28
  if ( strpos($v, 'widget-') === false ) continue;
29
  $sb[$k] = substr($v, strpos($v, '_') + 1);
30
  }
@@ -37,26 +37,26 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
37
  foreach($crtSidebars as $sidebarName => $values)
38
  {
39
  if(is_array($values) && ! empty($values) && isset($dbSidebars[$sidebarName]))
40
- {
41
- foreach($values as $widgetName)
42
- {
43
- if(! in_array($widgetName, $dbSidebars[$sidebarName]))
44
- {
45
- $toSidebar = $sidebarName;
46
- $wName = $widgetName;
47
- foreach($dbSidebars as $name => $v)
48
- {
49
- if(is_array($v) && !empty($v) && in_array($widgetName, $v))
50
- {
51
- $fromSidebar = $name;
52
- break;
53
- }
54
- }
55
- }
56
- }
57
  }
58
  }
59
-
60
  if (empty($wName) || empty($fromSidebar) || empty($toSidebar)) return;
61
 
62
  if(preg_match('/^sidebar-/', $fromSidebar) || preg_match('/^sidebar-/', $toSidebar)){
@@ -69,168 +69,167 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
69
  }
70
 
71
  $this->plugin->alerts->Trigger(2045, array(
72
- 'WidgetName' => $wName,
73
- 'OldSidebar' => $fromSidebar,
74
- 'NewSidebar' => $toSidebar,
75
- ));
76
  }
77
- }
78
-
79
- public function EventWidgetPostMove(){
80
- //#!-- generates the event 2071
81
- if(isset($_REQUEST['action'])&&($_REQUEST['action']=='widgets-order'))
82
- {
83
- if(isset($_REQUEST['sidebars']) && !empty($_REQUEST['sidebars'])){
84
- // Get the sidebars from $_REQUEST
85
- $requestSidebars = array();
86
- if($_REQUEST['sidebars']){
87
- foreach($_REQUEST['sidebars'] as $key => &$value){
88
- if(!empty($value)){
89
- // build the sidebars array
90
- $value = explode(',', $value);
91
- // Cleanup widgets' name
92
- foreach($value as $k => &$widgetName){
93
- $widgetName = preg_replace("/^([a-z]+-[0-9]+)+?_/i",'', $widgetName);
94
- }
95
- $requestSidebars[$key] = $value;
96
- }
97
- }
98
- }
99
-
100
- if($requestSidebars){
101
- // Get the sidebars from DATABASE
102
- $sidebar_widgets = wp_get_sidebars_widgets();
103
- // Get global sidebars so we can retrieve the real name of the sidebar
104
- global $wp_registered_sidebars;
105
 
106
- // Check in each array if there's any change
107
- foreach($requestSidebars as $sidebarName => $widgets){
108
- if(isset($sidebar_widgets[$sidebarName])){
 
 
109
 
110
- foreach($sidebar_widgets[$sidebarName] as $i => $widgetName){
111
- $index = array_search($widgetName, $widgets);
112
- // check to see whether or not the widget has been moved
113
- if($i != $index) {
114
- $sn = $sidebarName;
115
- // Try to retrieve the real name of the sidebar, otherwise fall-back to id: $sidebarName
116
- if($wp_registered_sidebars && isset($wp_registered_sidebars[$sidebarName])) {
117
- $sn = $wp_registered_sidebars[$sidebarName]['name'];
118
- }
119
- $this->plugin->alerts->Trigger(2071, array(
120
- 'WidgetName' => $widgetName,
121
- 'OldPosition' => $i+1,
122
- 'NewPosition' => $index+1,
123
- 'Sidebar' => $sn,
124
- ));
125
- }
126
- }
127
- }
128
- }
129
- }
130
- }
131
- }
132
- //#!--
 
 
 
133
 
134
- if($this->_WidgetMoveData){
135
- $wName = $this->_WidgetMoveData['widget'];
136
- $fromSidebar = $this->_WidgetMoveData['from'];
137
- $toSidebar = $this->_WidgetMoveData['to'];
138
-
139
- global $wp_registered_sidebars;
140
-
141
- if(preg_match('/^sidebar-/', $fromSidebar))
142
- $fromSidebar = isset($wp_registered_sidebars[$fromSidebar])
143
- ? $wp_registered_sidebars[$fromSidebar]['name']
144
- : $fromSidebar
145
- ;
146
- if(preg_match('/^sidebar-/', $toSidebar))
147
- $toSidebar = isset($wp_registered_sidebars[$toSidebar])
148
- ? $wp_registered_sidebars[$toSidebar]['name']
149
- : $toSidebar
150
- ;
151
-
152
- $this->plugin->alerts->Trigger(2045, array(
153
- 'WidgetName' => $wName,
154
- 'OldSidebar' => $fromSidebar,
155
- 'NewSidebar' => $toSidebar,
156
- ));
157
- }
158
- }
159
-
160
- public function EventWidgetActivity(){
161
  if(!isset($_POST) || !isset($_POST['widget-id']) || empty($_POST['widget-id'])){
162
  return;
163
  }
164
-
165
  $postData = $_POST;
166
  global $wp_registered_sidebars;
167
  $canCheckSidebar = (empty($wp_registered_sidebars) ? false : true);
168
-
169
- switch(true){
170
-
171
- // added widget
172
- case isset($postData['add_new']) && $postData['add_new'] == 'multi':
173
- $sidebar = $postData['sidebar'];
174
- if($canCheckSidebar && preg_match('/^sidebar-/', $sidebar)){
175
- $sidebar = $wp_registered_sidebars[$sidebar]['name'];
176
- }
177
- $this->plugin->alerts->Trigger(2042, array(
178
- 'WidgetName' => $postData['id_base'],
179
- 'Sidebar' => $sidebar,
180
- ));
181
- break;
182
-
183
- // deleted widget
184
- case isset($postData['delete_widget']) && intval($postData['delete_widget']) == 1:
185
- $sidebar = $postData['sidebar'];
186
- if($canCheckSidebar && preg_match('/^sidebar-/',$sidebar)){
187
- $sidebar = $wp_registered_sidebars[$sidebar]['name'];
188
- }
189
- $this->plugin->alerts->Trigger(2044, array(
190
- 'WidgetName' => $postData['id_base'],
191
- 'Sidebar' => $sidebar,
192
- ));
193
- break;
194
-
195
- // modified widget
196
- case isset($postData['id_base']) && !empty($postData['id_base']):
197
- $wId = 0;
198
- if(!empty($postData['multi_number'])){
199
- $wId = intval($postData['multi_number']);
200
- }elseif(!empty($postData['widget_number'])){
201
- $wId = intval($postData['widget_number']);
202
- }
203
- if(empty($wId))return;
204
 
205
- $wName = $postData['id_base'];
206
- $sidebar = $postData['sidebar'];
207
- $wData = isset($postData["widget-$wName"][$wId])
208
- ? $postData["widget-$wName"][$wId]
209
- : null;
210
 
211
- if(empty($wData))return;
212
 
213
- // get info from db
214
- $wdbData = get_option("widget_".$wName);
215
- if(empty($wdbData[$wId]))return;
216
 
217
- // transform 'on' -> 1
218
- foreach($wData as $k => $v)if($v == 'on')$wData[$k] = 1;
219
 
220
- // compare - checks for any changes inside widgets
221
- $diff = array_diff_assoc($wData, $wdbData[$wId]);
222
- $count = count($diff);
223
- if($count > 0){
224
- if($canCheckSidebar && preg_match("/^sidebar-/",$sidebar)){
225
- $sidebar = $wp_registered_sidebars[$sidebar]['name'];
226
- }
227
- $this->plugin->alerts->Trigger(2043, array(
228
- 'WidgetName' => $wName,
229
- 'Sidebar' => $sidebar,
230
- ));
231
- }
232
- break;
233
-
234
- }
235
- }
236
  }
2
 
3
  class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
4
 
5
+ public function HookEvents() {
6
+ if(current_user_can("edit_theme_options")) {
7
+ add_action('admin_init', array($this, 'EventWidgetMove'));
8
+ add_action('admin_init', array($this, 'EventWidgetPostMove'));
9
+ }
10
+ add_action('sidebar_admin_setup', array($this, 'EventWidgetActivity'));
11
+ }
12
 
13
+ protected $_WidgetMoveData = null;
14
+
15
+ public function EventWidgetMove(){
16
  if(isset($_POST) && !empty($_POST['sidebars']))
17
+ {
18
  $crtSidebars = $_POST['sidebars'];
19
  $sidebars = array();
20
  foreach ( $crtSidebars as $key => $val )
21
+ {
22
  $sb = array();
23
  if ( !empty($val) )
24
+ {
25
  $val = explode(',', $val);
26
  foreach ( $val as $k => $v )
27
+ {
28
  if ( strpos($v, 'widget-') === false ) continue;
29
  $sb[$k] = substr($v, strpos($v, '_') + 1);
30
  }
37
  foreach($crtSidebars as $sidebarName => $values)
38
  {
39
  if(is_array($values) && ! empty($values) && isset($dbSidebars[$sidebarName]))
40
+ {
41
+ foreach($values as $widgetName)
42
+ {
43
+ if(! in_array($widgetName, $dbSidebars[$sidebarName]))
44
+ {
45
+ $toSidebar = $sidebarName;
46
+ $wName = $widgetName;
47
+ foreach($dbSidebars as $name => $v)
48
+ {
49
+ if(is_array($v) && !empty($v) && in_array($widgetName, $v))
50
+ {
51
+ $fromSidebar = $name;
52
+ continue;
53
+ }
54
+ }
55
+ }
56
+ }
57
  }
58
  }
59
+
60
  if (empty($wName) || empty($fromSidebar) || empty($toSidebar)) return;
61
 
62
  if(preg_match('/^sidebar-/', $fromSidebar) || preg_match('/^sidebar-/', $toSidebar)){
69
  }
70
 
71
  $this->plugin->alerts->Trigger(2045, array(
72
+ 'WidgetName' => $wName,
73
+ 'OldSidebar' => $fromSidebar,
74
+ 'NewSidebar' => $toSidebar,
75
+ ));
76
  }
77
+ }
78
+
79
+ public function EventWidgetPostMove() {
80
+ //#!-- generates the event 2071
81
+ if (isset($_REQUEST['action'])&&($_REQUEST['action']=='widgets-order'))
82
+ {
83
+ if (isset($_REQUEST['sidebars'])) {
84
+ // Get the sidebars from $_REQUEST
85
+ $requestSidebars = array();
86
+ if ($_REQUEST['sidebars']) {
87
+ foreach($_REQUEST['sidebars'] as $key => &$value){
88
+ if(!empty($value)){
89
+ // build the sidebars array
90
+ $value = explode(',', $value);
91
+ // Cleanup widgets' name
92
+ foreach($value as $k => &$widgetName){
93
+ $widgetName = preg_replace("/^([a-z]+-[0-9]+)+?_/i",'', $widgetName);
94
+ }
95
+ $requestSidebars[$key] = $value;
96
+ }
97
+ }
98
+ }
 
 
 
 
 
 
99
 
100
+ if ($requestSidebars) {
101
+ // Get the sidebars from DATABASE
102
+ $sidebar_widgets = wp_get_sidebars_widgets();
103
+ // Get global sidebars so we can retrieve the real name of the sidebar
104
+ global $wp_registered_sidebars;
105
 
106
+ // Check in each array if there's any change
107
+ foreach ($requestSidebars as $sidebarName => $widgets) {
108
+ if (isset($sidebar_widgets[$sidebarName])) {
109
+ foreach ($sidebar_widgets[$sidebarName] as $i => $widgetName) {
110
+ $index = array_search($widgetName, $widgets);
111
+ // check to see whether or not the widget has been moved
112
+ if ($i != $index) {
113
+ $sn = $sidebarName;
114
+ // Try to retrieve the real name of the sidebar, otherwise fall-back to id: $sidebarName
115
+ if ($wp_registered_sidebars && isset($wp_registered_sidebars[$sidebarName])) {
116
+ $sn = $wp_registered_sidebars[$sidebarName]['name'];
117
+ }
118
+ $this->plugin->alerts->Trigger(2071, array(
119
+ 'WidgetName' => $widgetName,
120
+ 'OldPosition' => $i+1,
121
+ 'NewPosition' => $index+1,
122
+ 'Sidebar' => $sn,
123
+ ));
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+ //#!--
132
 
133
+ if($this->_WidgetMoveData){
134
+ $wName = $this->_WidgetMoveData['widget'];
135
+ $fromSidebar = $this->_WidgetMoveData['from'];
136
+ $toSidebar = $this->_WidgetMoveData['to'];
137
+
138
+ global $wp_registered_sidebars;
139
+
140
+ if(preg_match('/^sidebar-/', $fromSidebar))
141
+ $fromSidebar = isset($wp_registered_sidebars[$fromSidebar])
142
+ ? $wp_registered_sidebars[$fromSidebar]['name']
143
+ : $fromSidebar
144
+ ;
145
+ if(preg_match('/^sidebar-/', $toSidebar))
146
+ $toSidebar = isset($wp_registered_sidebars[$toSidebar])
147
+ ? $wp_registered_sidebars[$toSidebar]['name']
148
+ : $toSidebar
149
+ ;
150
+
151
+ $this->plugin->alerts->Trigger(2045, array(
152
+ 'WidgetName' => $wName,
153
+ 'OldSidebar' => $fromSidebar,
154
+ 'NewSidebar' => $toSidebar,
155
+ ));
156
+ }
157
+ }
158
+
159
+ public function EventWidgetActivity(){
160
  if(!isset($_POST) || !isset($_POST['widget-id']) || empty($_POST['widget-id'])){
161
  return;
162
  }
163
+
164
  $postData = $_POST;
165
  global $wp_registered_sidebars;
166
  $canCheckSidebar = (empty($wp_registered_sidebars) ? false : true);
167
+
168
+ switch(true){
169
+
170
+ // added widget
171
+ case isset($postData['add_new']) && $postData['add_new'] == 'multi':
172
+ $sidebar = isset($postData['sidebar']) ? $postData['sidebar'] : null;
173
+ if($canCheckSidebar && preg_match('/^sidebar-/', $sidebar)){
174
+ $sidebar = $wp_registered_sidebars[$sidebar]['name'];
175
+ }
176
+ $this->plugin->alerts->Trigger(2042, array(
177
+ 'WidgetName' => $postData['id_base'],
178
+ 'Sidebar' => $sidebar,
179
+ ));
180
+ break;
181
+
182
+ // deleted widget
183
+ case isset($postData['delete_widget']) && intval($postData['delete_widget']) == 1:
184
+ $sidebar = isset($postData['sidebar']) ? $postData['sidebar'] : null;
185
+ if($canCheckSidebar && preg_match('/^sidebar-/',$sidebar)){
186
+ $sidebar = $wp_registered_sidebars[$sidebar]['name'];
187
+ }
188
+ $this->plugin->alerts->Trigger(2044, array(
189
+ 'WidgetName' => $postData['id_base'],
190
+ 'Sidebar' => $sidebar,
191
+ ));
192
+ break;
193
+
194
+ // modified widget
195
+ case isset($postData['id_base']) && !empty($postData['id_base']):
196
+ $wId = 0;
197
+ if(!empty($postData['multi_number'])){
198
+ $wId = intval($postData['multi_number']);
199
+ }elseif(!empty($postData['widget_number'])){
200
+ $wId = intval($postData['widget_number']);
201
+ }
202
+ if(empty($wId))return;
203
 
204
+ $wName = $postData['id_base'];
205
+ $sidebar = isset($postData['sidebar']) ? $postData['sidebar'] : null;
206
+ $wData = isset($postData["widget-$wName"][$wId])
207
+ ? $postData["widget-$wName"][$wId]
208
+ : null;
209
 
210
+ if(empty($wData))return;
211
 
212
+ // get info from db
213
+ $wdbData = get_option("widget_".$wName);
214
+ if(empty($wdbData[$wId]))return;
215
 
216
+ // transform 'on' -> 1
217
+ foreach($wData as $k => $v)if($v == 'on')$wData[$k] = 1;
218
 
219
+ // compare - checks for any changes inside widgets
220
+ $diff = array_diff_assoc($wData, $wdbData[$wId]);
221
+ $count = count($diff);
222
+ if($count > 0){
223
+ if($canCheckSidebar && preg_match("/^sidebar-/",$sidebar)){
224
+ $sidebar = $wp_registered_sidebars[$sidebar]['name'];
225
+ }
226
+ $this->plugin->alerts->Trigger(2043, array(
227
+ 'WidgetName' => $wName,
228
+ 'Sidebar' => $sidebar,
229
+ ));
230
+ }
231
+ break;
232
+
233
+ }
234
+ }
235
  }
classes/Settings.php CHANGED
@@ -1,578 +1,621 @@
1
  <?php
2
  class WSAL_Settings {
3
- /**
4
- * @var WpSecurityAuditLog
5
- */
6
- protected $_plugin;
7
- public function __construct(WpSecurityAuditLog $plugin) {
8
- $this->_plugin = $plugin;
9
- }
10
-
11
- // <editor-fold desc="Developer Options">
12
- const OPT_DEV_DATA_INSPECTOR = 'd';
13
- const OPT_DEV_PHP_ERRORS = 'p';
14
- const OPT_DEV_REQUEST_LOG = 'r';
15
- const OPT_DEV_BACKTRACE_LOG = 'b';
16
 
17
- const ERROR_CODE_INVALID_IP = 901;
18
 
19
- protected $_devoption = null;
20
- /**
21
- * @return array Array of developer options to be enabled by default.
22
- */
23
- public function GetDefaultDevOptions(){
24
- return array();
25
- }
26
- /**
27
- * Returns whether a developer option is enabled or not.
28
- * @param string $option See self::OPT_DEV_* constants.
29
- * @return boolean If option is enabled or not.
30
- */
31
- public function IsDevOptionEnabled($option){
32
- if(is_null($this->_devoption)){
33
- $this->_devoption = $this->_plugin->GetGlobalOption(
34
- 'dev-options',
35
- implode(',', $this->GetDefaultDevOptions())
36
- );
37
- $this->_devoption = explode(',', $this->_devoption);
38
- }
39
- return in_array($option, $this->_devoption);
40
- }
41
- /**
42
- * @return boolean Whether any developer option has been enabled or not.
43
- */
44
- public function IsAnyDevOptionEnabled(){
45
- return !!$this->_plugin->GetGlobalOption('dev-options', null);
46
- }
47
- /**
48
- * Sets whether a developer option is enabled or not.
49
- * @param string $option See self::OPT_DEV_* constants.
50
- * @param boolean $enabled If option should be enabled or not.
51
- */
52
- public function SetDevOptionEnabled($option, $enabled){
53
- // make sure options have been loaded
54
- $this->IsDevOptionEnabled('');
55
- // remove option if it exists
56
- while(($p = array_search($option, $this->_devoption)) !== false)
57
- unset($this->_devoption[$p]);
58
- // add option if callee wants it enabled
59
- if($enabled)
60
- $this->_devoption[] = $option;
61
- // commit option
62
- $this->_plugin->SetGlobalOption(
63
- 'dev-options',
64
- implode(',', $this->_devoption)
65
- );
66
- }
67
- /**
68
- * Remove all enabled developer options.
69
- */
70
- public function ClearDevOptions(){
71
- $this->_devoption = array();
72
- $this->_plugin->SetGlobalOption('dev-options', '');
73
- }
74
- /**
75
- * @return boolean Whether to enable data inspector or not.
76
- */
77
- public function IsDataInspectorEnabled(){
78
- return $this->IsDevOptionEnabled(self::OPT_DEV_DATA_INSPECTOR);
79
- }
80
- /**
81
- * @return boolean Whether to PHP error logging or not.
82
- */
83
- public function IsPhpErrorLoggingEnabled(){
84
- return $this->IsDevOptionEnabled(self::OPT_DEV_PHP_ERRORS);
85
- }
86
- /**
87
- * @return boolean Whether to log requests to file or not.
88
- */
89
- public function IsRequestLoggingEnabled(){
90
- return $this->IsDevOptionEnabled(self::OPT_DEV_REQUEST_LOG);
91
- }
92
- /**
93
- * @return boolean Whether to store debug backtrace for PHP alerts or not.
94
- */
95
- public function IsBacktraceLoggingEnabled(){
96
- return $this->IsDevOptionEnabled(self::OPT_DEV_BACKTRACE_LOG);
97
- }
98
-
99
- // </editor-fold>
100
- /**
101
- * @return boolean Whether dashboard widgets are enabled or not.
102
- */
103
- public function IsWidgetsEnabled(){
104
- return !$this->_plugin->GetGlobalOption('disable-widgets');
105
- }
106
- /**
107
- * @param boolean $newvalue Whether dashboard widgets are enabled or not.
108
- */
109
- public function SetWidgetsEnabled($newvalue){
110
- $this->_plugin->SetGlobalOption('disable-widgets', !$newvalue);
111
- }
112
- /**
113
- * @return boolean Whether alerts in audit log view refresh automatically or not.
114
- */
115
- public function IsRefreshAlertsEnabled(){
116
- return !$this->_plugin->GetGlobalOption('disable-refresh');
117
- }
118
- /**
119
- * @param boolean $newvalue Whether alerts in audit log view refresh automatically or not.
120
- */
121
- public function SetRefreshAlertsEnabled($newvalue){
122
- $this->_plugin->SetGlobalOption('disable-refresh', !$newvalue);
123
- }
124
- /**
125
- * @return int Maximum number of alerts to show in dashboard widget.
126
- */
127
- public function GetDashboardWidgetMaxAlerts(){
128
- return 5;
129
- }
130
-
131
- // <editor-fold desc="Pruning Settings">
132
- /**
133
- * @return int The maximum number of alerts allowable.
134
- */
135
- public function GetMaxAllowedAlerts(){
136
- return 5000;
137
- }
138
- /**
139
- * @return string The default pruning date.
140
- */
141
- public function GetDefaultPruningDate(){
142
- return '1 month';
143
- }
144
- protected $_pruning = 0;
145
- /**
146
- * @return string The current pruning date.
147
- */
148
- public function GetPruningDate(){
149
- if(!$this->_pruning){
150
- $this->_pruning = $this->_plugin->GetGlobalOption('pruning-date');
151
- if(!strtotime($this->_pruning))
152
- $this->_pruning = $this->GetDefaultPruningDate();
153
- }
154
- return $this->_pruning;
155
- }
156
- /**
157
- * @param string $newvalue The new pruning date.
158
- */
159
- public function SetPruningDate($newvalue){
160
- if(strtotime($newvalue)){
161
- $this->_plugin->SetGlobalOption('pruning-date', $newvalue);
162
- $this->_pruning = $newvalue;
163
- }
164
- }
165
- /**
166
- * @return integer Maximum number of alerts to keep.
167
- */
168
- public function GetPruningLimit(){
169
- $val = (int)$this->_plugin->GetGlobalOption('pruning-limit');
170
- return $val ? $val : $this->GetMaxAllowedAlerts();
171
- }
172
- /**
173
- * @param integer $newvalue The new maximum number of alerts.
174
- */
175
- public function SetPruningLimit($newvalue){
176
- $newvalue = max(/*min(*/(int)$newvalue/*, $this->GetMaxAllowedAlerts())*/, 1);
177
- $this->_plugin->SetGlobalOption('pruning-limit', $newvalue);
178
- }
179
- public function SetPruningDateEnabled($enabled){
180
- $this->_plugin->SetGlobalOption('pruning-date-e', $enabled);
181
- }
182
- public function SetPruningLimitEnabled($enabled){
183
- $this->_plugin->SetGlobalOption('pruning-limit-e', $enabled);
184
- }
185
- public function IsPruningDateEnabled(){
186
- return $this->_plugin->GetGlobalOption('pruning-date-e');
187
- }
188
- public function IsPruningLimitEnabled(){
189
- return $this->_plugin->GetGlobalOption('pruning-limit-e');
190
- }
191
- public function IsRestrictAdmins(){
192
- return $this->_plugin->GetGlobalOption('restrict-admins', false);
193
- }
194
- /**
195
- * @deprecated Sandbox functionality is now in an external plugin.
196
- */
197
- public function IsSandboxPageEnabled(){
198
- $plugins = $this->_plugin->licensing->plugins();
199
- return isset($plugins['wsal-sandbox-extensionphp']);
200
- }
201
- public function SetRestrictAdmins($enable){
202
- $this->_plugin->SetGlobalOption('restrict-admins', (bool)$enable);
203
- }
204
-
205
- // </editor-fold>
206
- protected $_disabled = null;
207
- public function GetDefaultDisabledAlerts(){
208
- return array(0000, 0001, 0002, 0003, 0004, 0005);
209
- }
210
- /**
211
- * @return array IDs of disabled alerts.
212
- */
213
- public function GetDisabledAlerts(){
214
- if(!$this->_disabled){
215
- $this->_disabled = implode(',', $this->GetDefaultDisabledAlerts());
216
- $this->_disabled = $this->_plugin->GetGlobalOption('disabled-alerts', $this->_disabled);
217
- $this->_disabled = ($this->_disabled == '') ? array() : explode(',', $this->_disabled);
218
- $this->_disabled = array_map('intval', $this->_disabled);
219
- }
220
- return $this->_disabled;
221
- }
222
- /**
223
- * @param array $types IDs alerts to disable.
224
- */
225
- public function SetDisabledAlerts($types){
226
- $this->_disabled = array_unique(array_map('intval', $types));
227
- $this->_plugin->SetGlobalOption('disabled-alerts', implode(',', $this->_disabled));
228
- }
229
- public function IsIncognito(){
230
- return $this->_plugin->GetGlobalOption('hide-plugin');
231
- }
232
- public function SetIncognito($enabled){
233
- return $this->_plugin->SetGlobalOption('hide-plugin', $enabled);
234
- }
235
-
236
- /**
237
- * Checking if the data will be removed.
238
- */
239
- public function IsDeleteData(){
240
- return $this->_plugin->GetGlobalOption('delete-data');
241
- }
242
 
243
- public function SetDeleteData($enabled){
244
- return $this->_plugin->SetGlobalOption('delete-data', $enabled);
245
- }
246
 
247
- // <editor-fold desc="Access Control">
248
-
249
- protected $_viewers = null;
250
- public function SetAllowedPluginViewers($usersOrRoles){
251
- $this->_viewers = $usersOrRoles;
252
- $this->_plugin->SetGlobalOption('plugin-viewers', implode(',', $this->_viewers));
253
- }
254
- public function GetAllowedPluginViewers(){
255
- if(is_null($this->_viewers)){
256
- $this->_viewers = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-viewers'))));
257
- }
258
- return $this->_viewers;
259
- }
260
- protected $_editors = null;
261
- public function SetAllowedPluginEditors($usersOrRoles){
262
- $this->_editors = $usersOrRoles;
263
- $this->_plugin->SetGlobalOption('plugin-editors', implode(',', $this->_editors));
264
- }
265
- public function GetAllowedPluginEditors(){
266
- if(is_null($this->_editors)){
267
- $this->_editors = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-editors'))));
268
- }
269
- return $this->_editors;
270
- }
271
- protected $_perpage = null;
272
- public function SetViewPerPage($newvalue){
273
- $this->_perpage = max($newvalue, 1);
274
- $this->_plugin->SetGlobalOption('items-per-page', $this->_perpage);
275
- }
276
- public function GetViewPerPage(){
277
- if(is_null($this->_perpage)){
278
- $this->_perpage = (int)$this->_plugin->GetGlobalOption('items-per-page', 10);
279
- }
280
- return $this->_perpage;
281
- }
282
- /**
283
- * @param string $action Type of action, either 'view' or 'edit'.
284
- * @return boolean If user has access or not.
285
- */
286
- public function CurrentUserCan($action){
287
- return $this->UserCan(wp_get_current_user(), $action);
288
- }
289
- /**
290
- * @return string[] List of superadmin usernames.
291
- */
292
- protected function GetSuperAdmins(){
293
- return $this->_plugin->IsMultisite() ? get_super_admins() : array();
294
- }
295
- /**
296
- * @return string[] List of admin usernames.
297
- */
298
- protected function GetAdmins(){
299
- if($this->_plugin->IsMultisite()){
300
- // see: https://gist.github.com/1508426/65785a15b8638d43a9905effb59e4d97319ef8f8
301
- global $wpdb;
302
- $cap = $wpdb->prefix."capabilities";
303
- $sql = "SELECT DISTINCT $wpdb->users.user_login"
304
- . " FROM $wpdb->users"
305
- . " INNER JOIN $wpdb->usermeta ON ($wpdb->users.ID = $wpdb->usermeta.user_id )"
306
- . " WHERE $wpdb->usermeta.meta_key = '$cap'"
307
- . " AND CAST($wpdb->usermeta.meta_value AS CHAR) LIKE '%\"administrator\"%'";
308
- return $wpdb->get_col($sql);
309
- }else{
310
- $result = array();
311
- $query = 'role=administrator&fields[]=user_login';
312
- foreach (get_users($query) as $user) $result[] = $user->user_login;
313
- return $result;
314
- }
315
- }
316
- /**
317
- * Returns access tokens for a particular action.
318
- * @param string $action Type of action.
319
- * @return string[] List of tokens (usernames, roles etc).
320
- */
321
- public function GetAccessTokens($action){
322
- $allowed = array();
323
- switch($action){
324
- case 'view':
325
- $allowed = $this->GetAllowedPluginViewers();
326
- $allowed = array_merge($allowed, $this->GetAllowedPluginEditors());
327
- if (!$this->IsRestrictAdmins()) {
328
- $allowed = array_merge($allowed, $this->GetSuperAdmins());
329
- $allowed = array_merge($allowed, $this->GetAdmins());
330
- }
331
- break;
332
- case 'edit':
333
- $allowed = $this->GetAllowedPluginEditors();
334
- if (!$this->IsRestrictAdmins()) {
335
- $allowed = array_merge($allowed, $this->_plugin->IsMultisite() ?
336
- $this->GetSuperAdmins() : $this->GetAdmins()
337
- );
338
- }
339
- break;
340
- default:
341
- throw new Exception('Unknown action "'.$action.'".');
342
- }
343
- if (!$this->IsRestrictAdmins()) {
344
- if(is_multisite()){
345
- $allowed = array_merge($allowed, get_super_admins());
346
- }else{
347
- $allowed[] = 'administrator';
348
- }
349
- }
350
- return array_unique($allowed);
351
- }
352
- /**
353
- * @param integer|WP_user $user User object to check.
354
- * @param string $action Type of action, either 'view' or 'edit'.
355
- * @return boolean If user has access or not.
356
- */
357
- public function UserCan($user, $action){
358
- if(is_int($user))$user = get_userdata($user);
359
- $allowed = $this->GetAccessTokens($action);
360
- $check = array_merge(
361
- $user->roles,
362
- array($user->user_login)
363
- );
364
- foreach($check as $item){
365
- if(in_array($item, $allowed)){
366
- return true;
367
- }
368
- }
369
- return false;
370
- }
371
- public function GetCurrentUserRoles($baseRoles = null){
372
- if ($baseRoles == null) $baseRoles = wp_get_current_user()->roles;
373
- if (function_exists('is_super_admin') && is_super_admin()) $baseRoles[] = 'superadmin';
374
- return $baseRoles;
375
- }
376
 
377
- public function IsLoginSuperAdmin($username){
378
- $userId = username_exists($username);
379
- if ( function_exists('is_super_admin') && is_super_admin($userId) ) return true;
380
- else return false;
381
- }
382
-
383
- // </editor-fold>
384
-
385
- // <editor-fold desc="Licensing">
386
- public function GetLicenses(){
387
- return $this->_plugin->GetGlobalOption('licenses');
388
- }
389
- public function GetLicense($name){
390
- $data = $this->GetLicenses();
391
- $name = sanitize_key(basename($name));
392
- return isset($data[$name]) ? $data[$name] : array();
393
- }
394
- public function SetLicenses($data){
395
- $this->_plugin->SetGlobalOption('licenses', $data);
396
- }
397
- public function GetLicenseKey($name){
398
- $data = $this->GetLicense($name);
399
- return isset($data['key']) ? $data['key'] : '';
400
- }
401
- public function GetLicenseStatus($name){
402
- $data = $this->GetLicense($name);
403
- return isset($data['sts']) ? $data['sts'] : '';
404
- }
405
- public function GetLicenseErrors($name){
406
- $data = $this->GetLicense($name);
407
- return isset($data['err']) ? $data['err'] : '';
408
- }
409
- public function SetLicenseKey($name, $key){
410
- $data = $this->GetLicenses();
411
- if (!isset($data[$name])) $data[$name] = array();
412
- $data[$name]['key'] = $key;
413
- $this->SetLicenses($data);
414
- }
415
- public function SetLicenseStatus($name, $status){
416
- $data = $this->GetLicenses();
417
- if (!isset($data[$name])) $data[$name] = array();
418
- $data[$name]['sts'] = $status;
419
- $this->SetLicenses($data);
420
- }
421
- public function SetLicenseErrors($name, $errors){
422
- $data = $this->GetLicenses();
423
- if (!isset($data[$name])) $data[$name] = array();
424
- $data[$name]['err'] = $errors;
425
- $this->SetLicenses($data);
426
- }
427
- public function ClearLicenses(){
428
- $this->SetLicenses(array());
429
- }
430
-
431
- // </editor-fold>
432
-
433
- // <editor-fold desc="Client IP Retrieval">
434
-
435
- public function IsMainIPFromProxy(){
436
- return $this->_plugin->GetGlobalOption('use-proxy-ip');
437
- }
438
- public function SetMainIPFromProxy($enabled){
439
- return $this->_plugin->SetGlobalOption('use-proxy-ip', $enabled);
440
- }
441
-
442
- public function IsInternalIPsFiltered(){
443
- return $this->_plugin->GetGlobalOption('filter-internal-ip');
444
- }
445
- public function SetInternalIPsFiltering($enabled){
446
- return $this->_plugin->SetGlobalOption('filter-internal-ip', $enabled);
447
- }
448
-
449
- public function GetMainClientIP(){
450
- $result = null;
451
- if ($this->IsMainIPFromProxy()) {
452
- // TODO the algorithm below just gets the first IP in the list...we might want to make this more intelligent somehow
453
- $result = $this->GetClientIPs();
454
- $result = reset($result);
455
- $result = isset($result[0]) ? $result[0] : null;
456
- } elseif(isset($_SERVER['REMOTE_ADDR'])) {
457
- $result = $this->NormalizeIP($_SERVER['REMOTE_ADDR']);
458
- if (!$this->ValidateIP($result)) {
459
- $result = "Error " . self::ERROR_CODE_INVALID_IP . ": Invalid IP Address";
460
- }
461
- }
462
- return $result;
463
- }
464
-
465
- public function GetClientIPs(){
466
- $ips = array();
467
- 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) {
468
- if (isset($_SERVER[$key])) {
469
- $ips[$key] = array();
470
- foreach (explode(',', $_SERVER[$key]) as $ip)
471
- if ($this->ValidateIP($ip = $this->NormalizeIP($ip)))
472
- $ips[$key][] = $ip;
473
- }
474
- }
475
- return $ips;
476
- }
477
-
478
- protected function NormalizeIP($ip){
479
- $ip = trim($ip);
480
- if(strpos($ip, ':') !== false && substr_count($ip, '.') == 3 && strpos($ip, '[') === false){
481
- // IPv4 with a port (eg: 11.22.33.44:80)
482
- $ip = explode(':', $ip);
483
- $ip = $ip[0];
484
- }else{
485
- // IPv6 with a port (eg: [::1]:80)
486
- $ip = explode(']', $ip);
487
- $ip = ltrim($ip[0], '[');
488
- }
489
- return $ip;
490
- }
491
-
492
- protected function ValidateIP($ip){
493
- $opts = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
494
- if ($this->IsInternalIPsFiltered()) $opts = $opts | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;
495
- $filteredIP = filter_var($ip, FILTER_VALIDATE_IP, $opts);
496
- if (!$filteredIP || empty($filteredIP)) {
497
- //Regex IPV4
498
- if (preg_match("/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/", $ip)) return $ip;
499
- //Regex IPV6
500
- elseif (preg_match("/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/", $ip)) return $ip;
501
 
502
- error_log("Invalid IP in ValidateIP function: ".$ip);
503
- return false;
504
- } else {
505
- return $filteredIP;
506
- }
507
- }
508
 
509
- /**
510
- * Users excluded from monitoring
511
- */
512
- protected $_excluded_users = array();
513
- public function SetExcludedMonitoringUsers($users)
514
- {
515
- $this->_excluded_users = $users;
516
- $this->_plugin->SetGlobalOption('excluded-users', implode(',', $this->_excluded_users));
517
- }
518
- public function GetExcludedMonitoringUsers()
519
- {
520
- if(empty($this->_excluded_users)){
521
- $this->_excluded_users = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-users'))));
522
- }
523
- return $this->_excluded_users;
524
- }
525
 
526
- /**
527
- * Roles excluded from monitoring
528
- */
529
- protected $_excluded_roles = array();
530
- public function SetExcludedMonitoringRoles($roles){
531
- $this->_excluded_roles = $roles;
532
- $this->_plugin->SetGlobalOption('excluded-roles', implode(',', $this->_excluded_roles));
533
- }
534
- public function GetExcludedMonitoringRoles(){
535
- if(empty($this->_excluded_roles)){
536
- $this->_excluded_roles = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-roles'))));
537
- }
538
- return $this->_excluded_roles;
539
- }
540
 
541
- /**
542
- * Custom fields excluded from monitoring
543
- */
544
- protected $_excluded_custom = array();
545
- public function SetExcludedMonitoringCustom($custom){
546
- $this->_excluded_custom = $custom;
547
- $this->_plugin->SetGlobalOption('excluded-custom', implode(',', $this->_excluded_custom));
548
- }
549
- public function GetExcludedMonitoringCustom(){
550
- if(empty($this->_excluded_custom)){
551
- $this->_excluded_custom = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-custom'))));
552
- asort($this->_excluded_custom);
553
- }
554
- return $this->_excluded_custom;
555
- }
556
 
557
- /**
558
- * Datetime format.
559
- * 24 hours or AM/PM
560
- */
561
- public function GetDatetimeFormat(){
562
- return $this->_plugin->GetGlobalOption('datetime-format', 0);
563
- }
 
 
 
 
 
 
 
564
 
565
- public function SetDatetimeFormat($newvalue){
566
- return $this->_plugin->SetGlobalOption('datetime-format', $newvalue);
567
- }
 
 
 
 
568
 
569
- public function GetAdapterConfig($name_field){
570
- return $this->_plugin->GetGlobalOption($name_field);
571
- }
572
 
573
- public function SetAdapterConfig($name_field, $newvalue){
574
- return $this->_plugin->SetGlobalOption($name_field, trim($newvalue));
575
- }
576
-
577
- // </editor-fold>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
  }
1
  <?php
2
  class WSAL_Settings {
3
+ /**
4
+ * @var WpSecurityAuditLog
5
+ */
6
+ protected $_plugin;
7
+ public function __construct(WpSecurityAuditLog $plugin) {
8
+ $this->_plugin = $plugin;
9
+ }
10
+
11
+ // <editor-fold desc="Developer Options">
12
+ const OPT_DEV_DATA_INSPECTOR = 'd';
13
+ const OPT_DEV_PHP_ERRORS = 'p';
14
+ const OPT_DEV_REQUEST_LOG = 'r';
15
+ const OPT_DEV_BACKTRACE_LOG = 'b';
16
 
17
+ const ERROR_CODE_INVALID_IP = 901;
18
 
19
+ protected $_devoption = null;
20
+ /**
21
+ * @return array Array of developer options to be enabled by default.
22
+ */
23
+ public function GetDefaultDevOptions(){
24
+ return array();
25
+ }
26
+ /**
27
+ * Returns whether a developer option is enabled or not.
28
+ * @param string $option See self::OPT_DEV_* constants.
29
+ * @return boolean If option is enabled or not.
30
+ */
31
+ public function IsDevOptionEnabled($option){
32
+ if(is_null($this->_devoption)){
33
+ $this->_devoption = $this->_plugin->GetGlobalOption(
34
+ 'dev-options',
35
+ implode(',', $this->GetDefaultDevOptions())
36
+ );
37
+ $this->_devoption = explode(',', $this->_devoption);
38
+ }
39
+ return in_array($option, $this->_devoption);
40
+ }
41
+ /**
42
+ * @return boolean Whether any developer option has been enabled or not.
43
+ */
44
+ public function IsAnyDevOptionEnabled(){
45
+ return !!$this->_plugin->GetGlobalOption('dev-options', null);
46
+ }
47
+ /**
48
+ * Sets whether a developer option is enabled or not.
49
+ * @param string $option See self::OPT_DEV_* constants.
50
+ * @param boolean $enabled If option should be enabled or not.
51
+ */
52
+ public function SetDevOptionEnabled($option, $enabled){
53
+ // make sure options have been loaded
54
+ $this->IsDevOptionEnabled('');
55
+ // remove option if it exists
56
+ while(($p = array_search($option, $this->_devoption)) !== false)
57
+ unset($this->_devoption[$p]);
58
+ // add option if callee wants it enabled
59
+ if($enabled)
60
+ $this->_devoption[] = $option;
61
+ // commit option
62
+ $this->_plugin->SetGlobalOption(
63
+ 'dev-options',
64
+ implode(',', $this->_devoption)
65
+ );
66
+ }
67
+ /**
68
+ * Remove all enabled developer options.
69
+ */
70
+ public function ClearDevOptions(){
71
+ $this->_devoption = array();
72
+ $this->_plugin->SetGlobalOption('dev-options', '');
73
+ }
74
+ /**
75
+ * @return boolean Whether to enable data inspector or not.
76
+ */
77
+ public function IsDataInspectorEnabled(){
78
+ return $this->IsDevOptionEnabled(self::OPT_DEV_DATA_INSPECTOR);
79
+ }
80
+ /**
81
+ * @return boolean Whether to PHP error logging or not.
82
+ */
83
+ public function IsPhpErrorLoggingEnabled(){
84
+ return $this->IsDevOptionEnabled(self::OPT_DEV_PHP_ERRORS);
85
+ }
86
+ /**
87
+ * @return boolean Whether to log requests to file or not.
88
+ */
89
+ public function IsRequestLoggingEnabled(){
90
+ return $this->IsDevOptionEnabled(self::OPT_DEV_REQUEST_LOG);
91
+ }
92
+ /**
93
+ * @return boolean Whether to store debug backtrace for PHP alerts or not.
94
+ */
95
+ public function IsBacktraceLoggingEnabled(){
96
+ return $this->IsDevOptionEnabled(self::OPT_DEV_BACKTRACE_LOG);
97
+ }
98
+
99
+ // </editor-fold>
100
+ /**
101
+ * @return boolean Whether dashboard widgets are enabled or not.
102
+ */
103
+ public function IsWidgetsEnabled(){
104
+ return !$this->_plugin->GetGlobalOption('disable-widgets');
105
+ }
106
+ /**
107
+ * @param boolean $newvalue Whether dashboard widgets are enabled or not.
108
+ */
109
+ public function SetWidgetsEnabled($newvalue){
110
+ $this->_plugin->SetGlobalOption('disable-widgets', !$newvalue);
111
+ }
112
+ /**
113
+ * @return boolean Whether alerts in audit log view refresh automatically or not.
114
+ */
115
+ public function IsRefreshAlertsEnabled(){
116
+ return !$this->_plugin->GetGlobalOption('disable-refresh');
117
+ }
118
+ /**
119
+ * @param boolean $newvalue Whether alerts in audit log view refresh automatically or not.
120
+ */
121
+ public function SetRefreshAlertsEnabled($newvalue){
122
+ $this->_plugin->SetGlobalOption('disable-refresh', !$newvalue);
123
+ }
124
+ /**
125
+ * @return int Maximum number of alerts to show in dashboard widget.
126
+ */
127
+ public function GetDashboardWidgetMaxAlerts(){
128
+ return 5;
129
+ }
130
+
131
+ // <editor-fold desc="Pruning Settings">
132
+ /**
133
+ * @return int The maximum number of alerts allowable.
134
+ */
135
+ public function GetMaxAllowedAlerts(){
136
+ return 5000;
137
+ }
138
+ /**
139
+ * @return string The default pruning date.
140
+ */
141
+ public function GetDefaultPruningDate(){
142
+ return '1 month';
143
+ }
144
+ protected $_pruning = 0;
145
+ /**
146
+ * @return string The current pruning date.
147
+ */
148
+ public function GetPruningDate(){
149
+ if(!$this->_pruning){
150
+ $this->_pruning = $this->_plugin->GetGlobalOption('pruning-date');
151
+ if(!strtotime($this->_pruning))
152
+ $this->_pruning = $this->GetDefaultPruningDate();
153
+ }
154
+ return $this->_pruning;
155
+ }
156
+ /**
157
+ * @param string $newvalue The new pruning date.
158
+ */
159
+ public function SetPruningDate($newvalue){
160
+ if(strtotime($newvalue)){
161
+ $this->_plugin->SetGlobalOption('pruning-date', $newvalue);
162
+ $this->_pruning = $newvalue;
163
+ }
164
+ }
165
+ /**
166
+ * @return integer Maximum number of alerts to keep.
167
+ */
168
+ public function GetPruningLimit(){
169
+ $val = (int)$this->_plugin->GetGlobalOption('pruning-limit');
170
+ return $val ? $val : $this->GetMaxAllowedAlerts();
171
+ }
172
+ /**
173
+ * @param integer $newvalue The new maximum number of alerts.
174
+ */
175
+ public function SetPruningLimit($newvalue){
176
+ $newvalue = max(/*min(*/(int)$newvalue/*, $this->GetMaxAllowedAlerts())*/, 1);
177
+ $this->_plugin->SetGlobalOption('pruning-limit', $newvalue);
178
+ }
179
+ public function SetPruningDateEnabled($enabled){
180
+ $this->_plugin->SetGlobalOption('pruning-date-e', $enabled);
181
+ }
182
+ public function SetPruningLimitEnabled($enabled){
183
+ $this->_plugin->SetGlobalOption('pruning-limit-e', $enabled);
184
+ }
185
+ public function IsPruningDateEnabled(){
186
+ return $this->_plugin->GetGlobalOption('pruning-date-e');
187
+ }
188
+ public function IsPruningLimitEnabled(){
189
+ return $this->_plugin->GetGlobalOption('pruning-limit-e');
190
+ }
191
+ public function IsRestrictAdmins(){
192
+ return $this->_plugin->GetGlobalOption('restrict-admins', false);
193
+ }
194
+ /**
195
+ * @deprecated Sandbox functionality is now in an external plugin.
196
+ */
197
+ public function IsSandboxPageEnabled(){
198
+ $plugins = $this->_plugin->licensing->plugins();
199
+ return isset($plugins['wsal-sandbox-extensionphp']);
200
+ }
201
+ public function SetRestrictAdmins($enable){
202
+ $this->_plugin->SetGlobalOption('restrict-admins', (bool)$enable);
203
+ }
204
+
205
+ // </editor-fold>
206
+ protected $_disabled = null;
207
+ public function GetDefaultDisabledAlerts(){
208
+ return array(0000, 0001, 0002, 0003, 0004, 0005);
209
+ }
210
+ /**
211
+ * @return array IDs of disabled alerts.
212
+ */
213
+ public function GetDisabledAlerts(){
214
+ if(!$this->_disabled){
215
+ $this->_disabled = implode(',', $this->GetDefaultDisabledAlerts());
216
+ $this->_disabled = $this->_plugin->GetGlobalOption('disabled-alerts', $this->_disabled);
217
+ $this->_disabled = ($this->_disabled == '') ? array() : explode(',', $this->_disabled);
218
+ $this->_disabled = array_map('intval', $this->_disabled);
219
+ }
220
+ return $this->_disabled;
221
+ }
222
+ /**
223
+ * @param array $types IDs alerts to disable.
224
+ */
225
+ public function SetDisabledAlerts($types){
226
+ $this->_disabled = array_unique(array_map('intval', $types));
227
+ $this->_plugin->SetGlobalOption('disabled-alerts', implode(',', $this->_disabled));
228
+ }
229
+ public function IsIncognito(){
230
+ return $this->_plugin->GetGlobalOption('hide-plugin');
231
+ }
232
+ public function SetIncognito($enabled){
233
+ return $this->_plugin->SetGlobalOption('hide-plugin', $enabled);
234
+ }
235
+
236
+ /**
237
+ * Checking if the data will be removed.
238
+ */
239
+ public function IsDeleteData(){
240
+ return $this->_plugin->GetGlobalOption('delete-data');
241
+ }
242
 
243
+ public function SetDeleteData($enabled){
244
+ return $this->_plugin->SetGlobalOption('delete-data', $enabled);
245
+ }
246
 
247
+ // <editor-fold desc="Access Control">
248
+
249
+ protected $_viewers = null;
250
+ public function SetAllowedPluginViewers($usersOrRoles){
251
+ $this->_viewers = $usersOrRoles;
252
+ $this->_plugin->SetGlobalOption('plugin-viewers', implode(',', $this->_viewers));
253
+ }
254
+ public function GetAllowedPluginViewers(){
255
+ if(is_null($this->_viewers)){
256
+ $this->_viewers = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-viewers'))));
257
+ }
258
+ return $this->_viewers;
259
+ }
260
+ protected $_editors = null;
261
+ public function SetAllowedPluginEditors($usersOrRoles){
262
+ $this->_editors = $usersOrRoles;
263
+ $this->_plugin->SetGlobalOption('plugin-editors', implode(',', $this->_editors));
264
+ }
265
+ public function GetAllowedPluginEditors(){
266
+ if(is_null($this->_editors)){
267
+ $this->_editors = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-editors'))));
268
+ }
269
+ return $this->_editors;
270
+ }
271
+ protected $_perpage = null;
272
+ public function SetViewPerPage($newvalue){
273
+ $this->_perpage = max($newvalue, 1);
274
+ $this->_plugin->SetGlobalOption('items-per-page', $this->_perpage);
275
+ }
276
+ public function GetViewPerPage(){
277
+ if(is_null($this->_perpage)){
278
+ $this->_perpage = (int)$this->_plugin->GetGlobalOption('items-per-page', 10);
279
+ }
280
+ return $this->_perpage;
281
+ }
282
+ /**
283
+ * @param string $action Type of action, either 'view' or 'edit'.
284
+ * @return boolean If user has access or not.
285
+ */
286
+ public function CurrentUserCan($action){
287
+ return $this->UserCan(wp_get_current_user(), $action);
288
+ }
289
+ /**
290
+ * @return string[] List of superadmin usernames.
291
+ */
292
+ protected function GetSuperAdmins(){
293
+ return $this->_plugin->IsMultisite() ? get_super_admins() : array();
294
+ }
295
+ /**
296
+ * @return string[] List of admin usernames.
297
+ */
298
+ protected function GetAdmins(){
299
+ if($this->_plugin->IsMultisite()){
300
+ // see: https://gist.github.com/1508426/65785a15b8638d43a9905effb59e4d97319ef8f8
301
+ global $wpdb;
302
+ $cap = $wpdb->prefix."capabilities";
303
+ $sql = "SELECT DISTINCT $wpdb->users.user_login"
304
+ . " FROM $wpdb->users"
305
+ . " INNER JOIN $wpdb->usermeta ON ($wpdb->users.ID = $wpdb->usermeta.user_id )"
306
+ . " WHERE $wpdb->usermeta.meta_key = '$cap'"
307
+ . " AND CAST($wpdb->usermeta.meta_value AS CHAR) LIKE '%\"administrator\"%'";
308
+ return $wpdb->get_col($sql);
309
+ }else{
310
+ $result = array();
311
+ $query = 'role=administrator&fields[]=user_login';
312
+ foreach (get_users($query) as $user) $result[] = $user->user_login;
313
+ return $result;
314
+ }
315
+ }
316
+ /**
317
+ * Returns access tokens for a particular action.
318
+ * @param string $action Type of action.
319
+ * @return string[] List of tokens (usernames, roles etc).
320
+ */
321
+ public function GetAccessTokens($action){
322
+ $allowed = array();
323
+ switch($action){
324
+ case 'view':
325
+ $allowed = $this->GetAllowedPluginViewers();
326
+ $allowed = array_merge($allowed, $this->GetAllowedPluginEditors());
327
+ if (!$this->IsRestrictAdmins()) {
328
+ $allowed = array_merge($allowed, $this->GetSuperAdmins());
329
+ $allowed = array_merge($allowed, $this->GetAdmins());
330
+ }
331
+ break;
332
+ case 'edit':
333
+ $allowed = $this->GetAllowedPluginEditors();
334
+ if (!$this->IsRestrictAdmins()) {
335
+ $allowed = array_merge($allowed, $this->_plugin->IsMultisite() ?
336
+ $this->GetSuperAdmins() : $this->GetAdmins()
337
+ );
338
+ }
339
+ break;
340
+ default:
341
+ throw new Exception('Unknown action "'.$action.'".');
342
+ }
343
+ if (!$this->IsRestrictAdmins()) {
344
+ if(is_multisite()){
345
+ $allowed = array_merge($allowed, get_super_admins());
346
+ }else{
347
+ $allowed[] = 'administrator';
348
+ }
349
+ }
350
+ return array_unique($allowed);
351
+ }
352
+ /**
353
+ * @param integer|WP_user $user User object to check.
354
+ * @param string $action Type of action, either 'view' or 'edit'.
355
+ * @return boolean If user has access or not.
356
+ */
357
+ public function UserCan($user, $action){
358
+ if(is_int($user))$user = get_userdata($user);
359
+ $allowed = $this->GetAccessTokens($action);
360
+ $check = array_merge(
361
+ $user->roles,
362
+ array($user->user_login)
363
+ );
364
+ foreach($check as $item){
365
+ if(in_array($item, $allowed)){
366
+ return true;
367
+ }
368
+ }
369
+ return false;
370
+ }
371
+ public function GetCurrentUserRoles($baseRoles = null){
372
+ if ($baseRoles == null) $baseRoles = wp_get_current_user()->roles;
373
+ if (function_exists('is_super_admin') && is_super_admin()) $baseRoles[] = 'superadmin';
374
+ return $baseRoles;
375
+ }
376
 
377
+ public function IsLoginSuperAdmin($username){
378
+ $userId = username_exists($username);
379
+ if ( function_exists('is_super_admin') && is_super_admin($userId) ) return true;
380
+ else return false;
381
+ }
382
+
383
+ // </editor-fold>
384
+
385
+ // <editor-fold desc="Licensing">
386
+ public function GetLicenses(){
387
+ return $this->_plugin->GetGlobalOption('licenses');
388
+ }
389
+ public function GetLicense($name){
390
+ $data = $this->GetLicenses();
391
+ $name = sanitize_key(basename($name));
392
+ return isset($data[$name]) ? $data[$name] : array();
393
+ }
394
+ public function SetLicenses($data){
395
+ $this->_plugin->SetGlobalOption('licenses', $data);
396
+ }
397
+ public function GetLicenseKey($name){
398
+ $data = $this->GetLicense($name);
399
+ return isset($data['key']) ? $data['key'] : '';
400
+ }
401
+ public function GetLicenseStatus($name){
402
+ $data = $this->GetLicense($name);
403
+ return isset($data['sts']) ? $data['sts'] : '';
404
+ }
405
+ public function GetLicenseErrors($name){
406
+ $data = $this->GetLicense($name);
407
+ return isset($data['err']) ? $data['err'] : '';
408
+ }
409
+ public function SetLicenseKey($name, $key){
410
+ $data = $this->GetLicenses();
411
+ if (!isset($data[$name])) $data[$name] = array();
412
+ $data[$name]['key'] = $key;
413
+ $this->SetLicenses($data);
414
+ }
415
+ public function SetLicenseStatus($name, $status){
416
+ $data = $this->GetLicenses();
417
+ if (!isset($data[$name])) $data[$name] = array();
418
+ $data[$name]['sts'] = $status;
419
+ $this->SetLicenses($data);
420
+ }
421
+ public function SetLicenseErrors($name, $errors){
422
+ $data = $this->GetLicenses();
423
+ if (!isset($data[$name])) $data[$name] = array();
424
+ $data[$name]['err'] = $errors;
425
+ $this->SetLicenses($data);
426
+ }
427
+ public function ClearLicenses(){
428
+ $this->SetLicenses(array());
429
+ }
430
+
431
+ // </editor-fold>
432
+
433
+ // <editor-fold desc="Client IP Retrieval">
434
+
435
+ public function IsMainIPFromProxy(){
436
+ return $this->_plugin->GetGlobalOption('use-proxy-ip');
437
+ }
438
+ public function SetMainIPFromProxy($enabled){
439
+ return $this->_plugin->SetGlobalOption('use-proxy-ip', $enabled);
440
+ }
441
+
442
+ public function IsInternalIPsFiltered(){
443
+ return $this->_plugin->GetGlobalOption('filter-internal-ip');
444
+ }
445
+ public function SetInternalIPsFiltering($enabled){
446
+ return $this->_plugin->SetGlobalOption('filter-internal-ip', $enabled);
447
+ }
448
+
449
+ public function GetMainClientIP(){
450
+ $result = null;
451
+ if ($this->IsMainIPFromProxy()) {
452
+ // TODO the algorithm below just gets the first IP in the list...we might want to make this more intelligent somehow
453
+ $result = $this->GetClientIPs();
454
+ $result = reset($result);
455
+ $result = isset($result[0]) ? $result[0] : null;
456
+ } elseif(isset($_SERVER['REMOTE_ADDR'])) {
457
+ $result = $this->NormalizeIP($_SERVER['REMOTE_ADDR']);
458
+ if (!$this->ValidateIP($result)) {
459
+ $result = "Error " . self::ERROR_CODE_INVALID_IP . ": Invalid IP Address";
460
+ }
461
+ }
462
+ return $result;
463
+ }
464
+
465
+ public function GetClientIPs(){
466
+ $ips = array();
467
+ 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) {
468
+ if (isset($_SERVER[$key])) {
469
+ $ips[$key] = array();
470
+ foreach (explode(',', $_SERVER[$key]) as $ip)
471
+ if ($this->ValidateIP($ip = $this->NormalizeIP($ip)))
472
+ $ips[$key][] = $ip;
473
+ }
474
+ }
475
+ return $ips;
476
+ }
477
+
478
+ protected function NormalizeIP($ip){
479
+ $ip = trim($ip);
480
+ if(strpos($ip, ':') !== false && substr_count($ip, '.') == 3 && strpos($ip, '[') === false){
481
+ // IPv4 with a port (eg: 11.22.33.44:80)
482
+ $ip = explode(':', $ip);
483
+ $ip = $ip[0];
484
+ }else{
485
+ // IPv6 with a port (eg: [::1]:80)
486
+ $ip = explode(']', $ip);
487
+ $ip = ltrim($ip[0], '[');
488
+ }
489
+ return $ip;
490
+ }
491
+
492
+ protected function ValidateIP($ip){
493
+ $opts = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
494
+ if ($this->IsInternalIPsFiltered()) $opts = $opts | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;
495
+ $filteredIP = filter_var($ip, FILTER_VALIDATE_IP, $opts);
496
+ if (!$filteredIP || empty($filteredIP)) {
497
+ //Regex IPV4
498
+ if (preg_match("/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/", $ip)) return $ip;
499
+ //Regex IPV6
500
+ elseif (preg_match("/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/", $ip)) return $ip;
501
 
502
+ error_log("Invalid IP in ValidateIP function: ".$ip);
503
+ return false;
504
+ } else {
505
+ return $filteredIP;
506
+ }
507
+ }
508
 
509
+ /**
510
+ * Users excluded from monitoring
511
+ */
512
+ protected $_excluded_users = array();
513
+ public function SetExcludedMonitoringUsers($users)
514
+ {
515
+ $this->_excluded_users = $users;
516
+ $this->_plugin->SetGlobalOption('excluded-users', implode(',', $this->_excluded_users));
517
+ }
518
+ public function GetExcludedMonitoringUsers()
519
+ {
520
+ if(empty($this->_excluded_users)){
521
+ $this->_excluded_users = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-users'))));
522
+ }
523
+ return $this->_excluded_users;
524
+ }
525
 
526
+ /**
527
+ * Roles excluded from monitoring
528
+ */
529
+ protected $_excluded_roles = array();
530
+ public function SetExcludedMonitoringRoles($roles){
531
+ $this->_excluded_roles = $roles;
532
+ $this->_plugin->SetGlobalOption('excluded-roles', implode(',', $this->_excluded_roles));
533
+ }
534
+ public function GetExcludedMonitoringRoles(){
535
+ if(empty($this->_excluded_roles)){
536
+ $this->_excluded_roles = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-roles'))));
537
+ }
538
+ return $this->_excluded_roles;
539
+ }
540
 
541
+ /**
542
+ * Custom fields excluded from monitoring
543
+ */
544
+ protected $_excluded_custom = array();
545
+ public function SetExcludedMonitoringCustom($custom){
546
+ $this->_excluded_custom = $custom;
547
+ $this->_plugin->SetGlobalOption('excluded-custom', implode(',', $this->_excluded_custom));
548
+ }
549
+ public function GetExcludedMonitoringCustom(){
550
+ if(empty($this->_excluded_custom)){
551
+ $this->_excluded_custom = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-custom'))));
552
+ asort($this->_excluded_custom);
553
+ }
554
+ return $this->_excluded_custom;
555
+ }
556
 
557
+ /**
558
+ * IP excluded from monitoring
559
+ */
560
+ protected $_excluded_ip = array();
561
+ public function SetExcludedMonitoringIP($ip){
562
+ $this->_excluded_ip = $ip;
563
+ $this->_plugin->SetGlobalOption('excluded-ip', implode(',', $this->_excluded_ip));
564
+ }
565
+ public function GetExcludedMonitoringIP(){
566
+ if(empty($this->_excluded_ip)){
567
+ $this->_excluded_ip = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-ip'))));
568
+ }
569
+ return $this->_excluded_ip;
570
+ }
571
 
572
+ /**
573
+ * Datetime format.
574
+ * 24 hours or AM/PM
575
+ */
576
+ public function GetDatetimeFormat(){
577
+ return $this->_plugin->GetGlobalOption('datetime-format', 0);
578
+ }
579
 
580
+ public function SetDatetimeFormat($newvalue){
581
+ return $this->_plugin->SetGlobalOption('datetime-format', $newvalue);
582
+ }
583
 
584
+ public function GetAdapterConfig($name_field){
585
+ return $this->_plugin->GetGlobalOption($name_field);
586
+ }
587
+
588
+ public function SetAdapterConfig($name_field, $newvalue){
589
+ return $this->_plugin->SetGlobalOption($name_field, trim($newvalue));
590
+ }
591
+
592
+ public function GetColumns(){
593
+ $columns = array('alert_code' => '1', 'type' => '1', 'date' => '1', 'username' => '1', 'source_ip' => '1', 'message' => '1');
594
+ $selected = $this->GetColumnsSelected();
595
+ if (!empty($selected)) {
596
+ $columns = array('alert_code' => '0', 'type' => '0', 'date' => '0', 'username' => '0', 'source_ip' => '0', 'message' => '0');
597
+ $selected = (array)json_decode($selected);
598
+ $columns = array_merge($columns, $selected);
599
+ return $columns;
600
+ } else {
601
+ return $columns;
602
+ }
603
+ }
604
+
605
+ public function GetColumnsSelected(){
606
+ return $this->_plugin->GetGlobalOption('columns');
607
+ }
608
+
609
+ public function SetColumns($columns){
610
+ return $this->_plugin->SetGlobalOption('columns', json_encode($columns));
611
+ }
612
+
613
+ public function IsWPBackend(){
614
+ return $this->_plugin->GetGlobalOption('wp-backend');
615
+ }
616
+
617
+ public function SetWPBackend($enabled){
618
+ return $this->_plugin->SetGlobalOption('wp-backend', $enabled);
619
+ }
620
+ // </editor-fold>
621
  }
classes/Views/Extensions.php CHANGED
@@ -34,6 +34,13 @@ class WSAL_Views_Extensions extends WSAL_AbstractView {
34
  <p><a class="button" href="http://www.wpsecurityauditlog.com/extensions/wordpress-email-notifications-add-on/?utm_source=plugin&utm_medium=extensionspage&utm_campaign=notifications" target="_blank"><?php _e('More Information', 'wp-security-audit-log'); ?></a></p>
35
  </div>
36
 
 
 
 
 
 
 
 
37
  <div class="activity-block">
38
  <h2><?php _e('Search Add-On', '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>
34
  <p><a class="button" href="http://www.wpsecurityauditlog.com/extensions/wordpress-email-notifications-add-on/?utm_source=plugin&utm_medium=extensionspage&utm_campaign=notifications" target="_blank"><?php _e('More Information', 'wp-security-audit-log'); ?></a></p>
35
  </div>
36
 
37
+ <div class="activity-block">
38
+ <h2><?php _e('External DB Add-On', 'wp-security-audit-log'); ?></h2>
39
+ <strong><?php _e('Save the WordPress Audit Log in an external database.', 'wp-security-audit-log'); ?></strong>
40
+ <p><?php _e('By saving the WordPress Audit Log in an external database you improve the security and performance of your WordPress websites and blogs. You also ensure that your WordPress is compliant to a number of mandatory regulatory compliance requirements business websites need to adhere to.', 'wp-security-audit-log'); ?></p>
41
+ <p><a class="button" href="http://www.wpsecurityauditlog.com/extensions/external-database-for-wp-security-audit-log/?utm_source=plugin&utm_medium=extensionspage&utm_campaign=externaldb" target="_blank"><?php _e('More Information', 'wp-security-audit-log'); ?></a></p>
42
+ </div>
43
+
44
  <div class="activity-block">
45
  <h2><?php _e('Search Add-On', 'wp-security-audit-log'); ?></h2>
46
  <strong><?php _e('Automatically Search for specific WordPress user and site activity in WordPress Security Audit Log.', 'wp-security-audit-log'); ?></strong>
classes/Views/Settings.php CHANGED
@@ -1,91 +1,96 @@
1
  <?php
2
  class WSAL_Views_Settings extends WSAL_AbstractView {
3
 
4
- public $adapterMsg = '';
5
-
6
- public function __construct(WpSecurityAuditLog $plugin) {
7
- parent::__construct($plugin);
8
 
9
- add_action('wp_ajax_AjaxCheckSecurityToken', array($this, 'AjaxCheckSecurityToken'));
10
- add_action('wp_ajax_AjaxRunCleanup', array($this, 'AjaxRunCleanup'));
11
- add_action('wp_ajax_AjaxGetAllUsers', array($this, 'AjaxGetAllUsers'));
12
- add_action('wp_ajax_AjaxGetAllRoles', array($this, 'AjaxGetAllRoles'));
13
- }
14
-
15
- public function HasPluginShortcutLink(){
16
- return true;
17
- }
18
-
19
- public function GetTitle() {
20
- return __('Settings', 'wp-security-audit-log');
21
- }
22
-
23
- public function GetIcon() {
24
- return 'dashicons-admin-generic';
25
- }
26
-
27
- public function GetName() {
28
- return __('Settings', 'wp-security-audit-log');
29
- }
30
-
31
- public function GetWeight() {
32
- return 3;
33
- }
34
-
35
- protected function GetTokenType($token){
36
- $users = array();
37
- foreach(get_users('blog_id=0&fields[]=user_login') as $obj)
38
- $users[] = $obj->user_login;
39
- $roles = array_keys(get_editable_roles());
40
-
41
- if(in_array($token, $users))return 'user';
42
- if(in_array($token, $roles))return 'role';
43
- return 'other';
44
- }
45
-
46
- protected function Save(){
47
- check_admin_referer('wsal-settings');
48
- $this->_plugin->settings->SetPruningDateEnabled($_REQUEST['PruneBy'] == 'date');
49
- $this->_plugin->settings->SetPruningDate($_REQUEST['PruningDate']);
50
- $this->_plugin->settings->SetPruningLimitEnabled($_REQUEST['PruneBy'] == 'limit');
51
- $this->_plugin->settings->SetPruningLimit($_REQUEST['PruningLimit']);
52
- $this->_plugin->settings->SetWidgetsEnabled($_REQUEST['EnableDashboardWidgets']);
53
- $this->_plugin->settings->SetAllowedPluginViewers(isset($_REQUEST['Viewers']) ? $_REQUEST['Viewers'] : array());
54
- $this->_plugin->settings->SetAllowedPluginEditors(isset($_REQUEST['Editors']) ? $_REQUEST['Editors'] : array());
55
 
56
- $this->_plugin->settings->SetExcludedMonitoringUsers(isset($_REQUEST['ExUsers']) ? $_REQUEST['ExUsers'] : array());
57
- $this->_plugin->settings->SetExcludedMonitoringRoles(isset($_REQUEST['ExRoles']) ? $_REQUEST['ExRoles'] : array());
58
- $this->_plugin->settings->SetExcludedMonitoringCustom(isset($_REQUEST['Customs']) ? $_REQUEST['Customs'] : array());
 
59
 
60
- $this->_plugin->settings->SetRestrictAdmins(isset($_REQUEST['RestrictAdmins']));
61
- $this->_plugin->settings->SetRefreshAlertsEnabled($_REQUEST['EnableAuditViewRefresh']);
62
- $this->_plugin->settings->SetMainIPFromProxy(isset($_REQUEST['EnableProxyIpCapture']));
63
- $this->_plugin->settings->SetInternalIPsFiltering(isset($_REQUEST['EnableIpFiltering']));
64
- $this->_plugin->settings->SetIncognito(isset($_REQUEST['Incognito']));
65
- $this->_plugin->settings->SetDeleteData(isset($_REQUEST['DeleteData']));
66
- $this->_plugin->settings->SetDatetimeFormat($_REQUEST['DatetimeFormat']);
67
- $this->_plugin->settings->ClearDevOptions();
 
 
 
 
68
 
69
- if(isset($_REQUEST['DevOptions'])) {
70
- foreach($_REQUEST['DevOptions'] as $opt) {
71
- $this->_plugin->settings->SetDevOptionEnabled($opt, true);
72
- }
73
- }
74
 
75
- //
76
- // Database Adapter Settings
77
- // Temporarily not used
78
- //
79
- /* Check Adapter config */
80
- if (!empty($_REQUEST["AdapterUser"]) && ($_REQUEST['AdapterUser'] != '') && ($_REQUEST['AdapterName'] != '') && ($_REQUEST['AdapterHostname'] != '') ) {
81
- WSAL_Connector_ConnectorFactory::CheckConfig(
82
- trim($_REQUEST['AdapterType']),
83
- trim($_REQUEST['AdapterUser']),
84
- trim($_REQUEST['AdapterPassword']),
85
- trim($_REQUEST['AdapterName']),
86
- trim($_REQUEST['AdapterHostname']),
87
- trim($_REQUEST['AdapterBasePrefix'])
88
- );
89
 
90
  /* Setting Adapter config */
91
  $this->_plugin->settings->SetAdapterConfig('adapter-type', $_REQUEST['AdapterType']);
@@ -150,509 +155,501 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
150
  <img src="<?php echo $this->_plugin->GetBaseUrl(); ?>/img/reporting_250x150.gif" width="250" height="150" alt=""/>
151
  </a>
152
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
- <div class="nav-tabs">
155
- <table class="form-table wsal-tab widefat" id="tab-general">
156
- <tbody>
157
- <tr>
158
- <th><label for="delete1"><?php _e('Security Alerts Pruning', 'wp-security-audit-log'); ?></label></th>
159
- <td>
160
- <fieldset>
161
- <?php $text = __('(eg: 1 month)', 'wp-security-audit-log'); ?>
162
- <?php $nbld = !($this->_plugin->settings->IsPruningDateEnabled() || $this->_plugin->settings->IsPruningLimitEnabled()); ?>
163
- <label for="delete0">
164
- <input type="radio" id="delete0" name="PruneBy" value="" <?php if($nbld)echo 'checked="checked"'; ?>/>
165
- <?php echo __('None', 'wp-security-audit-log'); ?>
166
- </label>
167
- </fieldset>
168
- <fieldset>
169
- <?php $text = __('(eg: 1 month)', 'wp-security-audit-log'); ?>
170
- <?php $nbld = $this->_plugin->settings->IsPruningDateEnabled(); ?>
171
- <label for="delete1">
172
- <input type="radio" id="delete1" name="PruneBy" value="date" <?php if($nbld)echo 'checked="checked"'; ?>/>
173
- <?php echo __('Delete alerts older than', 'wp-security-audit-log'); ?>
174
- </label>
175
- <input type="text" id="PruningDate" name="PruningDate" placeholder="<?php echo $text; ?>"
176
- value="<?php echo esc_attr($this->_plugin->settings->GetPruningDate()); ?>"
177
- onfocus="jQuery('#delete1').attr('checked', true);"/>
178
- <span> <?php echo $text; ?></span>
179
- </fieldset>
180
- <fieldset>
181
- <?php $text = __('(eg: 80)', 'wp-security-audit-log'); ?>
182
- <?php $nbld = $this->_plugin->settings->IsPruningLimitEnabled(); ?>
183
- <label for="delete2">
184
- <input type="radio" id="delete2" name="PruneBy" value="limit" <?php if($nbld)echo 'checked="checked"'; ?>/>
185
- <?php echo __('Keep up to', 'wp-security-audit-log'); ?>
186
- </label>
187
- <input type="text" id="PruningLimit" name="PruningLimit" placeholder="<?php echo $text;?>"
188
- value="<?php echo esc_attr($this->_plugin->settings->GetPruningLimit()); ?>"
189
- onfocus="jQuery('#delete2').attr('checked', true);"/>
190
- <?php echo __('alerts', 'wp-security-audit-log'); ?>
191
- <span><?php echo $text; ?></span>
192
- </fieldset>
193
- <p class="description"><?php
194
- echo __('Next Scheduled Cleanup is in ', 'wp-security-audit-log');
195
- echo human_time_diff(current_time('timestamp'), $next = wp_next_scheduled('wsal_cleanup'));
196
- echo '<!-- ' . date('dMy H:i:s', $next) . ' --> ';
197
- echo sprintf(
198
- __('(or %s)', 'wp-security-audit-log'),
199
- '<a href="' . admin_url('admin-ajax.php?action=AjaxRunCleanup') . '">' . __('Run Manually', 'wp-security-audit-log') . '</a>'
200
- );
201
- ?></p>
202
- </td>
203
- </tr>
204
- <tr>
205
- <th><label for="dwoption_on"><?php _e('Alerts Dashboard Widget', 'wp-security-audit-log'); ?></label></th>
206
- <td>
207
- <fieldset>
208
- <?php $dwe = $this->_plugin->settings->IsWidgetsEnabled(); ?>
209
- <label for="dwoption_on">
210
- <input type="radio" name="EnableDashboardWidgets" id="dwoption_on" style="margin-top: 2px;" <?php if($dwe)echo 'checked="checked"'; ?> value="1">
211
- <span><?php _e('On', 'wp-security-audit-log'); ?></span>
212
- </label>
213
- <br/>
214
- <label for="dwoption_off">
215
- <input type="radio" name="EnableDashboardWidgets" id="dwoption_off" style="margin-top: 2px;" <?php if(!$dwe)echo 'checked="checked"'; ?> value="0">
216
- <span><?php _e('Off', 'wp-security-audit-log'); ?></span>
217
- </label>
218
- <br/>
219
- <p class="description"><?php
220
- echo sprintf(
221
- __('Display a dashboard widget with the latest %d security alerts.', 'wp-security-audit-log'),
222
- $this->_plugin->settings->GetDashboardWidgetMaxAlerts()
223
- );
224
- ?></p>
225
- </fieldset>
226
- </td>
227
- </tr>
228
- <tr>
229
- <th><label for="pioption_on"><?php _e('Reverse Proxy / Firewall Options', 'wp-security-audit-log'); ?></label></th>
230
- <td>
231
- <fieldset>
232
- <label for="EnableProxyIpCapture">
233
- <input type="checkbox" name="EnableProxyIpCapture" value="1" id="EnableProxyIpCapture"<?php
234
- if($this->_plugin->settings->IsMainIPFromProxy())echo ' checked="checked"';
235
- ?>/> <?php _e('WordPress running behind firewall or proxy', 'wp-security-audit-log'); ?><br/>
236
- <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>
237
- </label>
238
- <br/>
239
- <label for="EnableIpFiltering">
240
- <input type="checkbox" name="EnableIpFiltering" value="1" id="EnableIpFiltering"<?php
241
- if($this->_plugin->settings->IsInternalIPsFiltered())echo ' checked="checked"';
242
- ?>/> <?php _e('Filter Internal IP Addresses', 'wp-security-audit-log'); ?><br/>
243
- <span class="description"><?php _e('Enable this option to filter internal IP addresses from the proxy headers.', 'wp-security-audit-log'); ?></span>
244
- </label>
245
- </fieldset>
246
- </td>
247
- </tr>
248
- <tr>
249
- <th><label for="ViewerQueryBox"><?php _e('Can View Alerts', 'wp-security-audit-log'); ?></label></th>
250
- <td>
251
- <fieldset>
252
- <input type="text" id="ViewerQueryBox" style="float: left; display: block; width: 250px;">
253
- <input type="button" id="ViewerQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
254
- <br style="clear: both;"/>
255
- <p class="description"><?php
256
- _e('Users and Roles in this list can view the security alerts', 'wp-security-audit-log');
257
- ?></p>
258
- <div id="ViewerList"><?php
259
- foreach($this->_plugin->settings->GetAllowedPluginViewers() as $item){
260
- ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
261
- <input type="hidden" name="Viewers[]" value="<?php echo esc_attr($item); ?>"/>
262
- <?php echo esc_html($item); ?>
263
- <a href="javascript:;" title="Remove">&times;</a>
264
- </span><?php
265
- }
266
- ?></div>
267
- </fieldset>
268
- </td>
269
- </tr>
270
- <tr>
271
- <th><label for="EditorQueryBox"><?php _e('Can Manage Plugin', 'wp-security-audit-log'); ?></label></th>
272
- <td>
273
- <fieldset>
274
- <input type="text" id="EditorQueryBox" style="float: left; display: block; width: 250px;">
275
- <input type="button" id="EditorQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
276
- <br style="clear: both;"/>
277
- <p class="description"><?php
278
- _e('Users and Roles in this list can manage the plugin settings', 'wp-security-audit-log');
279
- ?></p>
280
- <div id="EditorList"><?php
281
- foreach($this->_plugin->settings->GetAllowedPluginEditors() as $item){
282
- ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
283
- <input type="hidden" name="Editors[]" value="<?php echo esc_attr($item); ?>"/>
284
- <?php echo esc_html($item); ?>
285
- <a href="javascript:;" title="Remove">&times;</a>
286
- </span><?php
287
- }
288
- ?></div>
289
- </fieldset>
290
- </td>
291
- </tr>
292
- <tr>
293
- <th><label for="RestrictAdmins"><?php _e('Restrict Plugin Access', 'wp-security-audit-log'); ?></label></th>
294
- <td>
295
- <fieldset>
296
- <input type="hidden" id="RestrictAdminsDefaultUser" value="<?php echo esc_attr(wp_get_current_user()->user_login); ?>"/>
297
- <label for="RestrictAdmins">
298
- <?php $ira = $this->_plugin->settings->IsRestrictAdmins(); ?>
299
- <input type="checkbox" name="RestrictAdmins" id="RestrictAdmins"<?php if($ira)echo ' checked="checked"'; ?>/>
300
- <span class="description">
301
- <?php _e('By default all the administrators on this WordPress have access to manage this plugin.<br/>By enabling this option only the users specified in the two options above and your username will have access to view alerts and manage this plugin.', 'wp-security-audit-log'); ?>
302
- </span>
303
- </label>
304
- </fieldset>
305
- </td>
306
- </tr>
307
- <tr>
308
- <th><label for="aroption_on"><?php _e('Refresh Audit Log Viewer', 'wp-security-audit-log'); ?></label></th>
309
- <td>
310
- <fieldset>
311
- <?php $are = $this->_plugin->settings->IsRefreshAlertsEnabled(); ?>
312
- <label for="aroption_on">
313
- <input type="radio" name="EnableAuditViewRefresh" id="aroption_on" style="margin-top: 2px;" <?php if($are)echo 'checked="checked"'; ?> value="1">
314
- <span><?php _e('Automatic', 'wp-security-audit-log'); ?></span>
315
- </label>
316
- <span class="description"> &mdash; <?php _e('Refresh Audit Log Viewer as soon as there are new alerts.', 'wp-security-audit-log'); ?></span>
317
- <br/>
318
- <label for="aroption_off">
319
- <input type="radio" name="EnableAuditViewRefresh" id="aroption_off" style="margin-top: 2px;" <?php if(!$are)echo 'checked="checked"'; ?> value="0">
320
- <span><?php _e('Manual', 'wp-security-audit-log'); ?></span>
321
- </label>
322
- <span class="description"> &mdash; <?php _e('Refresh Audit Log Viewer only when the page is reloaded.', 'wp-security-audit-log'); ?></span>
323
- <br/>
324
- </fieldset>
325
- </td>
326
- </tr>
327
- <tr>
328
- <th><label for="datetime_format_24"><?php _e('Alerts Time Format', 'wp-security-audit-log'); ?></label></th>
329
- <td>
330
- <fieldset>
331
- <?php $datetime = $this->_plugin->settings->GetDatetimeFormat(); ?>
332
- <label for="datetime_format_24">
333
- <input type="radio" name="DatetimeFormat" id="datetime_format_24" style="margin-top: 2px;" <?php if($datetime)echo 'checked="checked"'; ?> value="1">
334
- <span><?php _e('24 hours', 'wp-security-audit-log'); ?></span>
335
- </label>
336
- <br/>
337
- <label for="datetime_format_default">
338
- <input type="radio" name="DatetimeFormat" id="datetime_format_default" style="margin-top: 2px;" <?php if(!$datetime)echo 'checked="checked"'; ?> value="0">
339
- <span><?php _e('AM/PM', 'wp-security-audit-log'); ?></span>
340
- </label>
341
- <br/>
342
- </fieldset>
343
- </td>
344
- </tr>
345
- <tr>
346
- <th><label><?php _e('Developer Options', 'wp-security-audit-log'); ?></label></th>
347
- <td>
348
- <fieldset>
349
- <?php $any = $this->_plugin->settings->IsAnyDevOptionEnabled(); ?>
350
- <a href="javascript:;" style="<?php if($any)echo 'display: none;'; ?>"
351
- onclick="jQuery(this).hide().next().show();">Show Developer Options</a>
352
- <div style="<?php if(!$any)echo 'display: none;'; ?>">
353
- <p style="border-left: 3px solid #FFD000; padding: 2px 8px; margin-left: 6px; margin-bottom: 16px;"><?php
354
- _e('Only enable these options on testing, staging and development websites. Enabling any of the settings below on LIVE websites may cause unintended side-effects including degraded performance.', 'wp-security-audit-log');
355
- ?></p><?php
356
- foreach(array(
357
- WSAL_Settings::OPT_DEV_DATA_INSPECTOR => array(
358
- __('Data Inspector', 'wp-security-audit-log'),
359
- __('View data logged for each triggered alert.', 'wp-security-audit-log')
360
- ),
361
- WSAL_Settings::OPT_DEV_PHP_ERRORS => array(
362
- __('PHP Errors', 'wp-security-audit-log'),
363
- __('Enables sensor for alerts generated from PHP.', 'wp-security-audit-log')
364
- ),
365
- WSAL_Settings::OPT_DEV_REQUEST_LOG => array(
366
- __('Request Log', 'wp-security-audit-log'),
367
- __('Enables logging request to file.', 'wp-security-audit-log')
368
- ),
369
- WSAL_Settings::OPT_DEV_BACKTRACE_LOG => array(
370
- __('Backtrace', 'wp-security-audit-log'),
371
- __('Log full backtrace for PHP-generated alerts.', 'wp-security-audit-log')
372
- ),
373
- ) as $opt => $info){
374
- ?><label for="devoption_<?php echo $opt; ?>">
375
- <input type="checkbox" name="DevOptions[]" id="devoption_<?php echo $opt; ?>" <?php
376
- if($this->_plugin->settings->IsDevOptionEnabled($opt))echo 'checked="checked"'; ?> value="<?php echo $opt; ?>">
377
- <span><?php echo $info[0]; ?></span>
378
- <?php if(isset($info[1]) && $info[1]){ ?>
379
- <span class="description"> &mdash; <?php echo $info[1]; ?></span>
380
- <?php }
381
- ?></label><br/><?php
382
- }
383
- ?></div>
384
- </fieldset>
385
- </td>
386
- </tr>
387
-
388
- <tr>
389
- <th><label for="Incognito"><?php _e('Hide Plugin in Plugins Page', 'wp-security-audit-log'); ?></label></th>
390
- <td>
391
- <fieldset>
392
- <label for="Incognito">
393
- <input type="checkbox" name="Incognito" value="1" id="Incognito"<?php
394
- if($this->_plugin->settings->IsIncognito())echo ' checked="checked"';
395
- ?>/> <?php _e('Hide', 'wp-security-audit-log'); ?>
396
- </label>
397
- <br/>
398
- <span class="description">
399
- <?php _e('To manually revert this setting set the value of option wsal-hide-plugin to 0 in the wp_options table.', 'wp-security-audit-log'); ?>
400
- </span>
401
- </fieldset>
402
- </td>
403
- </tr>
404
- <tr>
405
- <th><label for="DeleteData"><?php _e('Remove Data on Unistall', 'wp-security-audit-log'); ?></label></th>
406
- <td>
407
- <fieldset>
408
- <label for="DeleteData">
409
- <input type="checkbox" name="DeleteData" value="1" id="DeleteData" onclick="return delete_confirm(this);"<?php
410
- if($this->_plugin->settings->IsDeleteData())echo ' checked="checked"';
411
- ?>/> <span class="description">Check this box if you would like remove all data when the plugin is deleted.</span>
412
- </label>
413
- </fieldset>
414
- </td>
415
- </tr>
416
- </tbody>
417
- </table>
418
- <!-- End general Tab-->
419
- <table class="form-table wsal-tab widefat" id="tab-exclude">
420
- <tbody>
421
- <tr>
422
- <th><h2>Users &amp; Roles</h2></th>
423
- </tr>
424
- <tr>
425
- <td colspan="2">Any of the users and roles listed in the below options will be excluded from monitoring. This means that any change they do will not be logged.</td>
426
- </tr>
427
- <tr>
428
- <th><label for="ExUserQueryBox"><?php _e('Excluded Users', 'wp-security-audit-log'); ?></label></th>
429
- <td>
430
- <fieldset>
431
- <input type="text" id="ExUserQueryBox" style="float: left; display: block; width: 250px;">
432
- <input type="button" id="ExUserQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
433
- <br style="clear: both;"/>
434
- <div id="ExUserList"><?php
435
- foreach($this->_plugin->settings->GetExcludedMonitoringUsers() as $item){
436
- ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
437
- <input type="hidden" name="ExUsers[]" value="<?php echo esc_attr($item); ?>"/>
438
- <?php echo esc_html($item); ?>
439
- <a href="javascript:;" title="Remove">&times;</a>
440
- </span><?php
441
- }
442
- ?></div>
443
- </fieldset>
444
- </td>
445
- </tr>
446
- <tr>
447
- <th><label for="ExRoleQueryBox"><?php _e('Excluded Roles', 'wp-security-audit-log'); ?></label></th>
448
- <td>
449
- <fieldset>
450
- <input type="text" id="ExRoleQueryBox" style="float: left; display: block; width: 250px;">
451
- <input type="button" id="ExRoleQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
452
- <br style="clear: both;"/>
453
- <div id="ExRoleList"><?php
454
- foreach($this->_plugin->settings->GetExcludedMonitoringRoles() as $item){
455
- ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
456
- <input type="hidden" name="ExRoles[]" value="<?php echo esc_attr($item); ?>"/>
457
- <?php echo esc_html($item); ?>
458
- <a href="javascript:;" title="Remove">&times;</a>
459
- </span><?php
460
- }
461
- ?></div>
462
- </fieldset>
463
- </td>
464
- </tr>
465
- <tr>
466
- <th><h2>Custom Fields</h2></th>
467
- </tr>
468
- <tr>
469
- <td colspan="2">Any of the custom fields listed below will be excluded from monitoring. This means that if they are changed or updated the plugin will not log such activity.</td>
470
- </tr>
471
- <tr>
472
- <th><label for="CustomQueryBox"><?php _e('Excluded Custom Fields', 'wp-security-audit-log'); ?></label></th>
473
- <td>
474
- <fieldset>
475
- <input type="text" id="CustomQueryBox" style="float: left; display: block; width: 250px;">
476
- <input type="button" id="CustomQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
477
- <br style="clear: both;"/>
478
- <div id="CustomList"><?php
479
- foreach($this->_plugin->settings->GetExcludedMonitoringCustom() as $item){
480
- ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
481
- <input type="hidden" name="Customs[]" value="<?php echo esc_attr($item); ?>"/>
482
- <?php echo esc_html($item); ?>
483
- <a href="javascript:;" title="Remove">&times;</a>
484
- </span><?php
485
- }
486
- ?></div>
487
- </fieldset>
488
- </td>
489
- </tr>
490
- </tbody>
491
- </table>
492
- <?php
493
- //
494
- // Temporarily disabling this
495
- //
496
- /*
497
- <!-- End exclude objects Tab-->
498
- <table class="form-table wsal-tab widefat" id="adapter">
499
- <tbody>
500
- <tr>
501
- <th><h2>Type</h2></th>
502
- </tr>
503
- <tr>
504
- <th><label for="AdapterType"><?php _e('Adapter Type', 'wp-security-audit-log'); ?></label></th>
505
- <td>
506
- <fieldset>
507
- <?php $adapterType = strtolower($this->_plugin->settings->GetAdapterConfig('adapter-type')); ?>
508
- <select name="AdapterType" id="AdapterType">
509
- <option value="MySQL" <?=($adapterType == 'mysql')? 'selected="selected"' : '';?>>DB MySQL</option>
510
-
511
- </select>
512
- </fieldset>
513
- </td>
514
- </tr>
515
- <tr>
516
- <th><h2>Config</h2></th>
517
- </tr>
518
- <tr>
519
- <th><label for="AdapterUser"><?php _e('Database User', 'wp-security-audit-log'); ?></label></th>
520
- <td>
521
- <fieldset>
522
- <?php $adapterUser = $this->_plugin->settings->GetAdapterConfig('adapter-user'); ?>
523
- <input type="text" id="AdapterUser" name="AdapterUser" value="<?=$adapterUser?>" style="float: left; display: block; width: 250px;">
524
- </fieldset>
525
- </td>
526
- </tr>
527
- <tr>
528
- <th><label for="AdapterPassword"><?php _e('Database Password', 'wp-security-audit-log'); ?></label></th>
529
- <td>
530
- <fieldset>
531
- <?php $adapterPassword = $this->_plugin->settings->GetAdapterConfig('adapter-password'); ?>
532
- <input type="password" id="AdapterPassword" name="AdapterPassword" value="<?=$adapterPassword?>" style="float: left; display: block; width: 250px;">
533
- </fieldset>
534
- </td>
535
- </tr>
536
- <tr>
537
- <th><label for="AdapterName"><?php _e('Database Name', 'wp-security-audit-log'); ?></label></th>
538
- <td>
539
- <fieldset>
540
- <?php $adapterName = $this->_plugin->settings->GetAdapterConfig('adapter-name'); ?>
541
- <input type="text" id="AdapterName" name="AdapterName" value="<?=$adapterName?>" style="float: left; display: block; width: 250px;">
542
- </fieldset>
543
- </td>
544
- </tr>
545
- <tr>
546
- <th><label for="AdapterHostname"><?php _e('Database Hostname', 'wp-security-audit-log'); ?></label></th>
547
- <td>
548
- <fieldset>
549
- <?php $adapterHostname = $this->_plugin->settings->GetAdapterConfig('adapter-hostname'); ?>
550
- <input type="text" id="AdapterHostname" name="AdapterHostname" value="<?=$adapterHostname?>" style="float: left; display: block; width: 250px;">
551
- </fieldset>
552
- </td>
553
- </tr>
554
- <tr>
555
- <th><label for="AdapterBasePrefix"><?php _e('Database Base prefix', 'wp-security-audit-log'); ?></label></th>
556
- <td>
557
- <fieldset>
558
- <?php $adapterBasePrefix = $this->_plugin->settings->GetAdapterConfig('adapter-base-prefix'); ?>
559
- <input type="text" id="AdapterBasePrefix" name="AdapterBasePrefix" value="<?=$adapterBasePrefix?>" style="float: left; display: block; width: 250px;">
560
- </fieldset>
561
- </td>
562
- </tr>
563
- </tbody>
564
- </table>
565
- */
566
- ?>
567
- <!-- End Adapter Tab-->
568
- </div>
569
- <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="Save &amp; Test Changes"></p>
570
- </form>
571
- <script type="text/javascript">
572
- <!--
573
- function delete_confirm(elementRef)
574
- {
575
- if ( elementRef.checked )
576
- {
577
- if ( window.confirm('Do you want remove all data when the plugin is deleted?') == false )
578
- elementRef.checked = false;
579
- }
580
- }
581
- // -->
582
- </script><?php
583
- }
584
-
585
- public function Header(){
586
- wp_enqueue_style(
587
- 'settings',
588
- $this->_plugin->GetBaseUrl() . '/css/settings.css',
589
- array(),
590
- filemtime($this->_plugin->GetBaseDir() . '/css/settings.css')
591
- );
592
- ?><style type="text/css">
593
- .wsal-tab {
594
- display: none;
595
- }
596
- .wsal-tab tr.alert-incomplete td {
597
- color: #9BE;
598
- }
599
- .wsal-tab tr.alert-unavailable td {
600
- color: #CCC;
601
- }
602
- </style><?php
603
- }
604
-
605
- public function Footer() {
606
- wp_enqueue_script(
607
- 'settings',
608
- $this->_plugin->GetBaseUrl() . '/js/settings.js',
609
- array(),
610
- filemtime($this->_plugin->GetBaseDir() . '/js/settings.js')
611
- );
612
- ?><script type="text/javascript">
613
- jQuery(document).ready(function(){
614
- // tab handling code
615
- jQuery('#wsal-tabs>a').click(function(){
616
- jQuery('#wsal-tabs>a').removeClass('nav-tab-active');
617
- jQuery('table.wsal-tab').hide();
618
- jQuery(jQuery(this).addClass('nav-tab-active').attr('href')).show();
619
- });
620
- // show relevant tab
621
- var hashlink = jQuery('#wsal-tabs>a[href="' + location.hash + '"]');
622
- if(hashlink.length){
623
- hashlink.click();
624
- }else{
625
- jQuery('#wsal-tabs>a:first').click();
626
- }
627
- });
628
- </script><?php
629
- }
630
-
631
- public function AjaxGetAllUsers() {
632
- if(!$this->_plugin->settings->CurrentUserCan('view'))
633
- die('Access Denied.');
634
 
635
- $users = array();
636
- foreach ( get_users() as $user ) {
637
- if (strpos($user->user_login, $_GET['term']) !== false) {
638
- array_push($users, $user->user_login);
639
- }
640
- }
641
- echo json_encode($users);
642
- exit;
643
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644
 
645
- public function AjaxGetAllRoles() {
646
- if(!$this->_plugin->settings->CurrentUserCan('view'))
647
- die('Access Denied.');
648
-
649
- $roles = array();
650
- foreach ( get_editable_roles() as $role_name => $role_info ) {
651
- if (strpos($role_name, $_GET['term']) !== false) {
652
- array_push($roles, $role_name);
653
- }
654
- }
655
- echo json_encode($roles);
656
- exit;
657
- }
658
  }
1
  <?php
2
  class WSAL_Views_Settings extends WSAL_AbstractView {
3
 
4
+ public $adapterMsg = '';
5
+
6
+ public function __construct(WpSecurityAuditLog $plugin) {
7
+ parent::__construct($plugin);
8
 
9
+ add_action('wp_ajax_AjaxCheckSecurityToken', array($this, 'AjaxCheckSecurityToken'));
10
+ add_action('wp_ajax_AjaxRunCleanup', array($this, 'AjaxRunCleanup'));
11
+ add_action('wp_ajax_AjaxGetAllUsers', array($this, 'AjaxGetAllUsers'));
12
+ add_action('wp_ajax_AjaxGetAllRoles', array($this, 'AjaxGetAllRoles'));
13
+ }
14
+
15
+ public function HasPluginShortcutLink(){
16
+ return true;
17
+ }
18
+
19
+ public function GetTitle() {
20
+ return __('Settings', 'wp-security-audit-log');
21
+ }
22
+
23
+ public function GetIcon() {
24
+ return 'dashicons-admin-generic';
25
+ }
26
+
27
+ public function GetName() {
28
+ return __('Settings', 'wp-security-audit-log');
29
+ }
30
+
31
+ public function GetWeight() {
32
+ return 3;
33
+ }
34
+
35
+ protected function GetTokenType($token){
36
+ $users = array();
37
+ foreach(get_users('blog_id=0&fields[]=user_login') as $obj)
38
+ $users[] = $obj->user_login;
39
+ $roles = array_keys(get_editable_roles());
40
+
41
+ if(in_array($token, $users))return 'user';
42
+ if(in_array($token, $roles))return 'role';
43
+ return 'other';
44
+ }
45
+
46
+ protected function Save(){
47
+ check_admin_referer('wsal-settings');
48
+ $this->_plugin->settings->SetPruningDateEnabled($_REQUEST['PruneBy'] == 'date');
49
+ $this->_plugin->settings->SetPruningDate($_REQUEST['PruningDate']);
50
+ $this->_plugin->settings->SetPruningLimitEnabled($_REQUEST['PruneBy'] == 'limit');
51
+ $this->_plugin->settings->SetPruningLimit($_REQUEST['PruningLimit']);
52
+ $this->_plugin->settings->SetWidgetsEnabled($_REQUEST['EnableDashboardWidgets']);
53
+ $this->_plugin->settings->SetAllowedPluginViewers(isset($_REQUEST['Viewers']) ? $_REQUEST['Viewers'] : array());
54
+ $this->_plugin->settings->SetAllowedPluginEditors(isset($_REQUEST['Editors']) ? $_REQUEST['Editors'] : array());
55
 
56
+ $this->_plugin->settings->SetExcludedMonitoringUsers(isset($_REQUEST['ExUsers']) ? $_REQUEST['ExUsers'] : array());
57
+ $this->_plugin->settings->SetExcludedMonitoringRoles(isset($_REQUEST['ExRoles']) ? $_REQUEST['ExRoles'] : array());
58
+ $this->_plugin->settings->SetExcludedMonitoringCustom(isset($_REQUEST['Customs']) ? $_REQUEST['Customs'] : array());
59
+ $this->_plugin->settings->SetExcludedMonitoringIP(isset($_REQUEST['IpAddrs']) ? $_REQUEST['IpAddrs'] : array());
60
 
61
+ $this->_plugin->settings->SetRestrictAdmins(isset($_REQUEST['RestrictAdmins']));
62
+ $this->_plugin->settings->SetRefreshAlertsEnabled($_REQUEST['EnableAuditViewRefresh']);
63
+ $this->_plugin->settings->SetMainIPFromProxy(isset($_REQUEST['EnableProxyIpCapture']));
64
+ $this->_plugin->settings->SetInternalIPsFiltering(isset($_REQUEST['EnableIpFiltering']));
65
+ $this->_plugin->settings->SetIncognito(isset($_REQUEST['Incognito']));
66
+ $this->_plugin->settings->SetDeleteData(isset($_REQUEST['DeleteData']));
67
+ $this->_plugin->settings->SetDatetimeFormat($_REQUEST['DatetimeFormat']);
68
+ $this->_plugin->settings->SetWPBackend(isset($_REQUEST['WPBackend']));
69
+ if (!empty($_REQUEST['Columns'])) {
70
+ $this->_plugin->settings->SetColumns($_REQUEST['Columns']);
71
+ }
72
+ $this->_plugin->settings->ClearDevOptions();
73
 
74
+ if(isset($_REQUEST['DevOptions'])) {
75
+ foreach($_REQUEST['DevOptions'] as $opt) {
76
+ $this->_plugin->settings->SetDevOptionEnabled($opt, true);
77
+ }
78
+ }
79
 
80
+ //
81
+ // Database Adapter Settings
82
+ // Temporarily not used
83
+ //
84
+ /* Check Adapter config */
85
+ if (!empty($_REQUEST["AdapterUser"]) && ($_REQUEST['AdapterUser'] != '') && ($_REQUEST['AdapterName'] != '') && ($_REQUEST['AdapterHostname'] != '') ) {
86
+ WSAL_Connector_ConnectorFactory::CheckConfig(
87
+ trim($_REQUEST['AdapterType']),
88
+ trim($_REQUEST['AdapterUser']),
89
+ trim($_REQUEST['AdapterPassword']),
90
+ trim($_REQUEST['AdapterName']),
91
+ trim($_REQUEST['AdapterHostname']),
92
+ trim($_REQUEST['AdapterBasePrefix'])
93
+ );
94
 
95
  /* Setting Adapter config */
96
  $this->_plugin->settings->SetAdapterConfig('adapter-type', $_REQUEST['AdapterType']);
155
  <img src="<?php echo $this->_plugin->GetBaseUrl(); ?>/img/reporting_250x150.gif" width="250" height="150" alt=""/>
156
  </a>
157
  </div>
158
+ <div class="nav-tabs">
159
+ <table class="form-table wsal-tab widefat" id="tab-general">
160
+ <tbody>
161
+ <tr>
162
+ <th><label for="delete1"><?php _e('Security Alerts Pruning', 'wp-security-audit-log'); ?></label></th>
163
+ <td>
164
+ <fieldset>
165
+ <?php $text = __('(eg: 1 month)', 'wp-security-audit-log'); ?>
166
+ <?php $nbld = !($this->_plugin->settings->IsPruningDateEnabled() || $this->_plugin->settings->IsPruningLimitEnabled()); ?>
167
+ <label for="delete0">
168
+ <input type="radio" id="delete0" name="PruneBy" value="" <?php if($nbld)echo 'checked="checked"'; ?>/>
169
+ <?php echo __('None', 'wp-security-audit-log'); ?>
170
+ </label>
171
+ </fieldset>
172
+ <fieldset>
173
+ <?php $text = __('(eg: 1 month)', 'wp-security-audit-log'); ?>
174
+ <?php $nbld = $this->_plugin->settings->IsPruningDateEnabled(); ?>
175
+ <label for="delete1">
176
+ <input type="radio" id="delete1" name="PruneBy" value="date" <?php if($nbld)echo 'checked="checked"'; ?>/>
177
+ <?php echo __('Delete alerts older than', 'wp-security-audit-log'); ?>
178
+ </label>
179
+ <input type="text" id="PruningDate" name="PruningDate" placeholder="<?php echo $text; ?>"
180
+ value="<?php echo esc_attr($this->_plugin->settings->GetPruningDate()); ?>"
181
+ onfocus="jQuery('#delete1').attr('checked', true);"/>
182
+ <span> <?php echo $text; ?></span>
183
+ </fieldset>
184
+ <fieldset>
185
+ <?php $text = __('(eg: 80)', 'wp-security-audit-log'); ?>
186
+ <?php $nbld = $this->_plugin->settings->IsPruningLimitEnabled(); ?>
187
+ <label for="delete2">
188
+ <input type="radio" id="delete2" name="PruneBy" value="limit" <?php if($nbld)echo 'checked="checked"'; ?>/>
189
+ <?php echo __('Keep up to', 'wp-security-audit-log'); ?>
190
+ </label>
191
+ <input type="text" id="PruningLimit" name="PruningLimit" placeholder="<?php echo $text;?>"
192
+ value="<?php echo esc_attr($this->_plugin->settings->GetPruningLimit()); ?>"
193
+ onfocus="jQuery('#delete2').attr('checked', true);"/>
194
+ <?php echo __('alerts', 'wp-security-audit-log'); ?>
195
+ <span><?php echo $text; ?></span>
196
+ </fieldset>
197
+ <p class="description"><?php
198
+ echo __('Next Scheduled Cleanup is in ', 'wp-security-audit-log');
199
+ echo human_time_diff(current_time('timestamp'), $next = wp_next_scheduled('wsal_cleanup'));
200
+ echo '<!-- ' . date('dMy H:i:s', $next) . ' --> ';
201
+ echo sprintf(
202
+ __('(or %s)', 'wp-security-audit-log'),
203
+ '<a href="' . admin_url('admin-ajax.php?action=AjaxRunCleanup') . '">' . __('Run Manually', 'wp-security-audit-log') . '</a>'
204
+ );
205
+ ?></p>
206
+ </td>
207
+ </tr>
208
+ <tr>
209
+ <th><label for="dwoption_on"><?php _e('Alerts Dashboard Widget', 'wp-security-audit-log'); ?></label></th>
210
+ <td>
211
+ <fieldset>
212
+ <?php $dwe = $this->_plugin->settings->IsWidgetsEnabled(); ?>
213
+ <label for="dwoption_on">
214
+ <input type="radio" name="EnableDashboardWidgets" id="dwoption_on" style="margin-top: 2px;" <?php if($dwe)echo 'checked="checked"'; ?> value="1">
215
+ <span><?php _e('On', 'wp-security-audit-log'); ?></span>
216
+ </label>
217
+ <br/>
218
+ <label for="dwoption_off">
219
+ <input type="radio" name="EnableDashboardWidgets" id="dwoption_off" style="margin-top: 2px;" <?php if(!$dwe)echo 'checked="checked"'; ?> value="0">
220
+ <span><?php _e('Off', 'wp-security-audit-log'); ?></span>
221
+ </label>
222
+ <br/>
223
+ <p class="description"><?php
224
+ echo sprintf(
225
+ __('Display a dashboard widget with the latest %d security alerts.', 'wp-security-audit-log'),
226
+ $this->_plugin->settings->GetDashboardWidgetMaxAlerts()
227
+ );
228
+ ?></p>
229
+ </fieldset>
230
+ </td>
231
+ </tr>
232
+ <tr>
233
+ <th><label for="pioption_on"><?php _e('Reverse Proxy / Firewall Options', 'wp-security-audit-log'); ?></label></th>
234
+ <td>
235
+ <fieldset>
236
+ <label for="EnableProxyIpCapture">
237
+ <input type="checkbox" name="EnableProxyIpCapture" value="1" id="EnableProxyIpCapture"<?php
238
+ if($this->_plugin->settings->IsMainIPFromProxy())echo ' checked="checked"';
239
+ ?>/> <?php _e('WordPress running behind firewall or proxy', 'wp-security-audit-log'); ?><br/>
240
+ <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>
241
+ </label>
242
+ <br/>
243
+ <label for="EnableIpFiltering">
244
+ <input type="checkbox" name="EnableIpFiltering" value="1" id="EnableIpFiltering"<?php
245
+ if($this->_plugin->settings->IsInternalIPsFiltered())echo ' checked="checked"';
246
+ ?>/> <?php _e('Filter Internal IP Addresses', 'wp-security-audit-log'); ?><br/>
247
+ <span class="description"><?php _e('Enable this option to filter internal IP addresses from the proxy headers.', 'wp-security-audit-log'); ?></span>
248
+ </label>
249
+ </fieldset>
250
+ </td>
251
+ </tr>
252
+ <tr>
253
+ <th><label for="ViewerQueryBox"><?php _e('Can View Alerts', 'wp-security-audit-log'); ?></label></th>
254
+ <td>
255
+ <fieldset>
256
+ <input type="text" id="ViewerQueryBox" style="float: left; display: block; width: 250px;">
257
+ <input type="button" id="ViewerQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
258
+ <br style="clear: both;"/>
259
+ <p class="description"><?php
260
+ _e('Users and Roles in this list can view the security alerts', 'wp-security-audit-log');
261
+ ?></p>
262
+ <div id="ViewerList"><?php
263
+ foreach($this->_plugin->settings->GetAllowedPluginViewers() as $item){
264
+ ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
265
+ <input type="hidden" name="Viewers[]" value="<?php echo esc_attr($item); ?>"/>
266
+ <?php echo esc_html($item); ?>
267
+ <a href="javascript:;" title="Remove">&times;</a>
268
+ </span><?php
269
+ }
270
+ ?></div>
271
+ </fieldset>
272
+ </td>
273
+ </tr>
274
+ <tr>
275
+ <th><label for="EditorQueryBox"><?php _e('Can Manage Plugin', 'wp-security-audit-log'); ?></label></th>
276
+ <td>
277
+ <fieldset>
278
+ <input type="text" id="EditorQueryBox" style="float: left; display: block; width: 250px;">
279
+ <input type="button" id="EditorQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
280
+ <br style="clear: both;"/>
281
+ <p class="description"><?php
282
+ _e('Users and Roles in this list can manage the plugin settings', 'wp-security-audit-log');
283
+ ?></p>
284
+ <div id="EditorList"><?php
285
+ foreach($this->_plugin->settings->GetAllowedPluginEditors() as $item){
286
+ ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
287
+ <input type="hidden" name="Editors[]" value="<?php echo esc_attr($item); ?>"/>
288
+ <?php echo esc_html($item); ?>
289
+ <a href="javascript:;" title="Remove">&times;</a>
290
+ </span><?php
291
+ }
292
+ ?></div>
293
+ </fieldset>
294
+ </td>
295
+ </tr>
296
+ <tr>
297
+ <th><label for="RestrictAdmins"><?php _e('Restrict Plugin Access', 'wp-security-audit-log'); ?></label></th>
298
+ <td>
299
+ <fieldset>
300
+ <input type="hidden" id="RestrictAdminsDefaultUser" value="<?php echo esc_attr(wp_get_current_user()->user_login); ?>"/>
301
+ <label for="RestrictAdmins">
302
+ <?php $ira = $this->_plugin->settings->IsRestrictAdmins(); ?>
303
+ <input type="checkbox" name="RestrictAdmins" id="RestrictAdmins"<?php if($ira)echo ' checked="checked"'; ?>/>
304
+ <span class="description">
305
+ <?php _e('By default all the administrators on this WordPress have access to manage this plugin.<br/>By enabling this option only the users specified in the two options above and your username will have access to view alerts and manage this plugin.', 'wp-security-audit-log'); ?>
306
+ </span>
307
+ </label>
308
+ </fieldset>
309
+ </td>
310
+ </tr>
311
+ <tr>
312
+ <th><label for="aroption_on"><?php _e('Refresh Audit Log Viewer', 'wp-security-audit-log'); ?></label></th>
313
+ <td>
314
+ <fieldset>
315
+ <?php $are = $this->_plugin->settings->IsRefreshAlertsEnabled(); ?>
316
+ <label for="aroption_on">
317
+ <input type="radio" name="EnableAuditViewRefresh" id="aroption_on" style="margin-top: 2px;" <?php if($are)echo 'checked="checked"'; ?> value="1">
318
+ <span><?php _e('Automatic', 'wp-security-audit-log'); ?></span>
319
+ </label>
320
+ <span class="description"> &mdash; <?php _e('Refresh Audit Log Viewer as soon as there are new alerts.', 'wp-security-audit-log'); ?></span>
321
+ <br/>
322
+ <label for="aroption_off">
323
+ <input type="radio" name="EnableAuditViewRefresh" id="aroption_off" style="margin-top: 2px;" <?php if(!$are)echo 'checked="checked"'; ?> value="0">
324
+ <span><?php _e('Manual', 'wp-security-audit-log'); ?></span>
325
+ </label>
326
+ <span class="description"> &mdash; <?php _e('Refresh Audit Log Viewer only when the page is reloaded.', 'wp-security-audit-log'); ?></span>
327
+ <br/>
328
+ </fieldset>
329
+ </td>
330
+ </tr>
331
+ <tr>
332
+ <th><label for="datetime_format_24"><?php _e('Alerts Time Format', 'wp-security-audit-log'); ?></label></th>
333
+ <td>
334
+ <fieldset>
335
+ <?php $datetime = $this->_plugin->settings->GetDatetimeFormat(); ?>
336
+ <label for="datetime_format_24">
337
+ <input type="radio" name="DatetimeFormat" id="datetime_format_24" style="margin-top: 2px;" <?php if($datetime)echo 'checked="checked"'; ?> value="1">
338
+ <span><?php _e('24 hours', 'wp-security-audit-log'); ?></span>
339
+ </label>
340
+ <br/>
341
+ <label for="datetime_format_default">
342
+ <input type="radio" name="DatetimeFormat" id="datetime_format_default" style="margin-top: 2px;" <?php if(!$datetime)echo 'checked="checked"'; ?> value="0">
343
+ <span><?php _e('AM/PM', 'wp-security-audit-log'); ?></span>
344
+ </label>
345
+ <br/>
346
+ </fieldset>
347
+ </td>
348
+ </tr>
349
+ <tr>
350
+ <th><label for="columns"><?php _e('Audit Log Columns Selection', 'wp-security-audit-log'); ?></label></th>
351
+ <td>
352
+ <fieldset>
353
+ <?php $columns = $this->_plugin->settings->GetColumns(); ?>
354
+ <?php foreach ($columns as $key => $value) { ?>
355
+ <label for="columns">
356
+ <input type="checkbox" name="Columns[<?=$key?>]" id="<?=$key?>" class="sel-columns" style="margin-top: 2px;" <?php if ($value == '1') echo 'checked="checked"'; ?> value="1">
357
+ <span><?=ucwords(str_replace("_", " ", $key))?></span>
358
+ </label>
359
+ <br/>
360
+ <?php } ?>
361
+ <span class="description"><?php _e('When you disable any of the above such details won’t be shown in the Audit Log
362
+ viewer though the plugin will still record such information in the database.', 'wp-security-audit-log'); ?></span>
363
+ </fieldset>
364
+ </td>
365
+ </tr>
366
+ <tr>
367
+ <th><label><?php _e('Developer Options', 'wp-security-audit-log'); ?></label></th>
368
+ <td>
369
+ <fieldset>
370
+ <?php $any = $this->_plugin->settings->IsAnyDevOptionEnabled(); ?>
371
+ <a href="javascript:;" style="<?php if($any)echo 'display: none;'; ?>"
372
+ onclick="jQuery(this).hide().next().show();">Show Developer Options</a>
373
+ <div style="<?php if(!$any)echo 'display: none;'; ?>">
374
+ <p style="border-left: 3px solid #FFD000; padding: 2px 8px; margin-left: 6px; margin-bottom: 16px;"><?php
375
+ _e('Only enable these options on testing, staging and development websites. Enabling any of the settings below on LIVE websites may cause unintended side-effects including degraded performance.', 'wp-security-audit-log');
376
+ ?></p><?php
377
+ foreach (array(
378
+ WSAL_Settings::OPT_DEV_DATA_INSPECTOR => array(
379
+ __('Data Inspector', 'wp-security-audit-log'),
380
+ __('View data logged for each triggered alert.', 'wp-security-audit-log')
381
+ ),
382
+ WSAL_Settings::OPT_DEV_PHP_ERRORS => array(
383
+ __('PHP Errors', 'wp-security-audit-log'),
384
+ __('Enables sensor for alerts generated from PHP.', 'wp-security-audit-log')
385
+ ),
386
+ WSAL_Settings::OPT_DEV_REQUEST_LOG => array(
387
+ __('Request Log', 'wp-security-audit-log'),
388
+ __('Enables logging request to file.', 'wp-security-audit-log')
389
+ ),
390
+ WSAL_Settings::OPT_DEV_BACKTRACE_LOG => array(
391
+ __('Backtrace', 'wp-security-audit-log'),
392
+ __('Log full backtrace for PHP-generated alerts.', 'wp-security-audit-log')
393
+ ),
394
+ ) as $opt => $info) {
395
+ ?><label for="devoption_<?php echo $opt; ?>">
396
+ <input type="checkbox" name="DevOptions[]" id="devoption_<?php echo $opt; ?>" <?php
397
+ if($this->_plugin->settings->IsDevOptionEnabled($opt))echo 'checked="checked"'; ?> value="<?php echo $opt; ?>">
398
+ <span><?php echo $info[0]; ?></span>
399
+ <?php if (isset($info[1]) && $info[1]) { ?>
400
+ <span class="description"> &mdash; <?php echo $info[1]; ?></span>
401
+ <?php }
402
+ ?></label><br/><?php
403
+ }
404
+ ?></div>
405
+ </fieldset>
406
+ </td>
407
+ </tr>
408
+
409
+ <tr>
410
+ <th><label for="Incognito"><?php _e('Hide Plugin in Plugins Page', 'wp-security-audit-log'); ?></label></th>
411
+ <td>
412
+ <fieldset>
413
+ <label for="Incognito">
414
+ <input type="checkbox" name="Incognito" value="1" id="Incognito"<?php
415
+ if ($this->_plugin->settings->IsIncognito())echo ' checked="checked"';
416
+ ?>/> <?php _e('Hide', 'wp-security-audit-log'); ?>
417
+ </label>
418
+ <br/>
419
+ <span class="description">
420
+ <?php _e('To manually revert this setting set the value of option wsal-hide-plugin to 0 in the wp_options table.', 'wp-security-audit-log'); ?>
421
+ </span>
422
+ </fieldset>
423
+ </td>
424
+ </tr>
425
+ <tr>
426
+ <th><label for="DeleteData"><?php _e('Disable Alerts for WordPress Background Activity', 'wp-security-audit-log'); ?></label></th>
427
+ <td>
428
+ <fieldset>
429
+ <label for="WPBackend">
430
+ <input type="checkbox" name="WPBackend" value="1" id="WPBackend" <?php
431
+ if($this->_plugin->settings->IsWPBackend())echo ' checked="checked"';
432
+ ?>/> <?php _e('Hide activity', 'wp-security-audit-log'); ?>
433
+ </label>
434
+ <br/>
435
+ <span class="description">
436
+ <?php _e('For example do not raise an alert when WordPress deletes the auto drafts.', 'wp-security-audit-log'); ?>
437
+ </span>
438
+ </fieldset>
439
+ </td>
440
+ </tr>
441
+ <tr>
442
+ <th><label for="DeleteData"><?php _e('Remove Data on Unistall', 'wp-security-audit-log'); ?></label></th>
443
+ <td>
444
+ <fieldset>
445
+ <label for="DeleteData">
446
+ <input type="checkbox" name="DeleteData" value="1" id="DeleteData" onclick="return delete_confirm(this);"<?php
447
+ if($this->_plugin->settings->IsDeleteData())echo ' checked="checked"';
448
+ ?>/> <span class="description">Check this box if you would like remove all data when the plugin is deleted.</span>
449
+ </label>
450
+ </fieldset>
451
+ </td>
452
+ </tr>
453
+ </tbody>
454
+ </table>
455
+ <!-- End general Tab-->
456
+ <table class="form-table wsal-tab widefat" id="tab-exclude">
457
+ <tbody>
458
+ <tr>
459
+ <th><h2>Users &amp; Roles</h2></th>
460
+ </tr>
461
+ <tr>
462
+ <td colspan="2">Any of the users and roles listed in the below options will be excluded from monitoring. This means that any change they do will not be logged.</td>
463
+ </tr>
464
+ <tr>
465
+ <th><label for="ExUserQueryBox"><?php _e('Excluded Users', 'wp-security-audit-log'); ?></label></th>
466
+ <td>
467
+ <fieldset>
468
+ <input type="text" id="ExUserQueryBox" style="float: left; display: block; width: 250px;">
469
+ <input type="button" id="ExUserQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
470
+ <br style="clear: both;"/>
471
+ <div id="ExUserList"><?php
472
+ foreach($this->_plugin->settings->GetExcludedMonitoringUsers() as $item){
473
+ ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
474
+ <input type="hidden" name="ExUsers[]" value="<?php echo esc_attr($item); ?>"/>
475
+ <?php echo esc_html($item); ?>
476
+ <a href="javascript:;" title="Remove">&times;</a>
477
+ </span><?php
478
+ }
479
+ ?></div>
480
+ </fieldset>
481
+ </td>
482
+ </tr>
483
+ <tr>
484
+ <th><label for="ExRoleQueryBox"><?php _e('Excluded Roles', 'wp-security-audit-log'); ?></label></th>
485
+ <td>
486
+ <fieldset>
487
+ <input type="text" id="ExRoleQueryBox" style="float: left; display: block; width: 250px;">
488
+ <input type="button" id="ExRoleQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
489
+ <br style="clear: both;"/>
490
+ <div id="ExRoleList"><?php
491
+ foreach($this->_plugin->settings->GetExcludedMonitoringRoles() as $item){
492
+ ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
493
+ <input type="hidden" name="ExRoles[]" value="<?php echo esc_attr($item); ?>"/>
494
+ <?php echo esc_html($item); ?>
495
+ <a href="javascript:;" title="Remove">&times;</a>
496
+ </span><?php
497
+ }
498
+ ?></div>
499
+ </fieldset>
500
+ </td>
501
+ </tr>
502
+ <tr>
503
+ <th><h2>Custom Fields</h2></th>
504
+ </tr>
505
+ <tr>
506
+ <td colspan="2">Any of the custom fields listed below will be excluded from monitoring. This means that if they are changed or updated the plugin will not log such activity.</td>
507
+ </tr>
508
+ <tr>
509
+ <th><label for="CustomQueryBox"><?php _e('Excluded Custom Fields', 'wp-security-audit-log'); ?></label></th>
510
+ <td>
511
+ <fieldset>
512
+ <input type="text" id="CustomQueryBox" style="float: left; display: block; width: 250px;">
513
+ <input type="button" id="CustomQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
514
+ <br style="clear: both;"/>
515
+ <div id="CustomList"><?php
516
+ foreach($this->_plugin->settings->GetExcludedMonitoringCustom() as $item){
517
+ ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
518
+ <input type="hidden" name="Customs[]" value="<?php echo esc_attr($item); ?>"/>
519
+ <?php echo esc_html($item); ?>
520
+ <a href="javascript:;" title="Remove">&times;</a>
521
+ </span><?php
522
+ }
523
+ ?></div>
524
+ </fieldset>
525
+ </td>
526
+ </tr>
527
+ <tr>
528
+ <th><h2>IP Addresses</h2></th>
529
+ </tr>
530
+ <tr>
531
+ <td colspan="2">Any of the IP addresses listed below will be excluded from monitoring. This means that all activity from such IP address will not be recorded.</td>
532
+ </tr>
533
+ <tr>
534
+ <th><label for="IpAddrQueryBox"><?php _e('Excluded IP Addresses', 'wp-security-audit-log'); ?></label></th>
535
+ <td>
536
+ <fieldset>
537
+ <input type="text" id="IpAddrQueryBox" style="float: left; display: block; width: 250px;">
538
+ <input type="button" id="IpAddrQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
539
+ <br style="clear: both;"/>
540
+ <div id="IpAddrList"><?php
541
+ foreach($this->_plugin->settings->GetExcludedMonitoringIP() as $item){
542
+ ?><span class="sectoken-<?php echo $this->GetTokenType($item); ?>">
543
+ <input type="hidden" name="IpAddrs[]" value="<?php echo esc_attr($item); ?>"/>
544
+ <?php echo esc_html($item); ?>
545
+ <a href="javascript:;" title="Remove">&times;</a>
546
+ </span><?php
547
+ }
548
+ ?></div>
549
+ </fieldset>
550
+ </td>
551
+ </tr>
552
+ </tbody>
553
+ </table>
554
+ </div>
555
+ <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="Save Changes"></p>
556
+ </form>
557
+ <script type="text/javascript">
558
+ <!--
559
+ function delete_confirm(elementRef)
560
+ {
561
+ if ( elementRef.checked )
562
+ {
563
+ if ( window.confirm('Do you want remove all data when the plugin is deleted?') == false )
564
+ elementRef.checked = false;
565
+ }
566
+ }
567
+ // -->
568
+ </script><?php
569
+ }
570
+
571
+ public function Header(){
572
+ wp_enqueue_style(
573
+ 'settings',
574
+ $this->_plugin->GetBaseUrl() . '/css/settings.css',
575
+ array(),
576
+ filemtime($this->_plugin->GetBaseDir() . '/css/settings.css')
577
+ );
578
+ ?><style type="text/css">
579
+ .wsal-tab {
580
+ display: none;
581
+ }
582
+ .wsal-tab tr.alert-incomplete td {
583
+ color: #9BE;
584
+ }
585
+ .wsal-tab tr.alert-unavailable td {
586
+ color: #CCC;
587
+ }
588
+ </style><?php
589
+ }
590
+
591
+ public function Footer() {
592
+ wp_enqueue_script(
593
+ 'settings',
594
+ $this->_plugin->GetBaseUrl() . '/js/settings.js',
595
+ array(),
596
+ filemtime($this->_plugin->GetBaseDir() . '/js/settings.js')
597
+ );
598
+ ?><script type="text/javascript">
599
+ jQuery(document).ready(function(){
600
+ // tab handling code
601
+ jQuery('#wsal-tabs>a').click(function(){
602
+ jQuery('#wsal-tabs>a').removeClass('nav-tab-active');
603
+ jQuery('table.wsal-tab').hide();
604
+ jQuery(jQuery(this).addClass('nav-tab-active').attr('href')).show();
605
+ });
606
+ // show relevant tab
607
+ var hashlink = jQuery('#wsal-tabs>a[href="' + location.hash + '"]');
608
+ if (hashlink.length) {
609
+ hashlink.click();
610
+ } else {
611
+ jQuery('#wsal-tabs>a:first').click();
612
+ }
613
 
614
+ jQuery(".sel-columns").change(function(){
615
+ var notChecked = 1;
616
+ jQuery(".sel-columns").each(function(){
617
+ if(this.checked) notChecked = 0;
618
+ })
619
+ if(notChecked == 1){
620
+ alert("You have to select at least one column!");
621
+ }
622
+ });
623
+ });
624
+ </script><?php
625
+ }
626
+
627
+ public function AjaxGetAllUsers() {
628
+ if(!$this->_plugin->settings->CurrentUserCan('view'))
629
+ die('Access Denied.');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
630
 
631
+ $users = array();
632
+ foreach ( get_users() as $user ) {
633
+ if (strpos($user->user_login, $_GET['term']) !== false) {
634
+ array_push($users, $user->user_login);
635
+ }
636
+ }
637
+ echo json_encode($users);
638
+ exit;
639
+ }
640
+
641
+ public function AjaxGetAllRoles() {
642
+ if(!$this->_plugin->settings->CurrentUserCan('view'))
643
+ die('Access Denied.');
644
+
645
+ $roles = array();
646
+ foreach ( get_editable_roles() as $role_name => $role_info ) {
647
+ if (strpos($role_name, $_GET['term']) !== false) {
648
+ array_push($roles, $role_name);
649
+ }
650
+ }
651
+ echo json_encode($roles);
652
+ exit;
653
+ }
654
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  }
js/settings.js CHANGED
@@ -6,7 +6,7 @@ jQuery(document).ready(function(){
6
  });
7
  };
8
 
9
- jQuery('#ViewerQueryBox, #EditorQueryBox, #ExRoleQueryBox, #ExUserQueryBox, #CustomQueryBox').keydown(function(event){
10
  if(event.keyCode === 13) {
11
  var type = jQuery(this).attr('id').substr(0, 6);
12
  jQuery('#'+type+'QueryAdd').click();
@@ -14,7 +14,7 @@ jQuery(document).ready(function(){
14
  }
15
  });
16
 
17
- jQuery('#ViewerQueryAdd, #EditorQueryAdd, #ExRoleQueryAdd, #ExUserQueryAdd, #CustomQueryAdd').click(function(){
18
  var type = jQuery(this).attr('id').substr(0, 6);
19
  var value = jQuery.trim(jQuery('#'+type+'QueryBox').val());
20
  var existing = jQuery('#'+type+'List input').filter(function() { return this.value === value; });
@@ -24,8 +24,8 @@ jQuery(document).ready(function(){
24
  jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', true);
25
  jQuery.post(jQuery('#ajaxurl').val(), {action: 'AjaxCheckSecurityToken', token: value}, function(data){
26
  jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', false);
27
- if (type != 'Custom') {
28
- if(data==='other') {
29
  alert('The specified token is not a user nor a role!');
30
  jQuery('#'+type+'QueryBox').val('');
31
  return;
@@ -39,7 +39,7 @@ jQuery(document).ready(function(){
39
  });
40
  });
41
 
42
- jQuery('#ViewerList>span>a, #EditorList>span>a, #ExRoleList>span>a, #ExUserList>span>a, #CustomList>span>a').click(RemoveSecToken);
43
 
44
  jQuery('#RestrictAdmins').change(function(){
45
  var user = jQuery('#RestrictAdminsDefaultUser').val();
6
  });
7
  };
8
 
9
+ jQuery('#ViewerQueryBox, #EditorQueryBox, #ExRoleQueryBox, #ExUserQueryBox, #CustomQueryBox, #IpAddrQueryBox').keydown(function(event){
10
  if(event.keyCode === 13) {
11
  var type = jQuery(this).attr('id').substr(0, 6);
12
  jQuery('#'+type+'QueryAdd').click();
14
  }
15
  });
16
 
17
+ jQuery('#ViewerQueryAdd, #EditorQueryAdd, #ExRoleQueryAdd, #ExUserQueryAdd, #CustomQueryAdd, #IpAddrQueryAdd').click(function(){
18
  var type = jQuery(this).attr('id').substr(0, 6);
19
  var value = jQuery.trim(jQuery('#'+type+'QueryBox').val());
20
  var existing = jQuery('#'+type+'List input').filter(function() { return this.value === value; });
24
  jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', true);
25
  jQuery.post(jQuery('#ajaxurl').val(), {action: 'AjaxCheckSecurityToken', token: value}, function(data){
26
  jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', false);
27
+ if (type != 'Custom' && type != 'IpAddr') {
28
+ if(data === 'other') {
29
  alert('The specified token is not a user nor a role!');
30
  jQuery('#'+type+'QueryBox').val('');
31
  return;
39
  });
40
  });
41
 
42
+ jQuery('#ViewerList>span>a, #EditorList>span>a, #ExRoleList>span>a, #ExUserList>span>a, #CustomList>span>a, #IpAddrList>span>a').click(RemoveSecToken);
43
 
44
  jQuery('#RestrictAdmins').change(function(){
45
  var user = jQuery('#RestrictAdminsDefaultUser').val();
languages/wp-security-audit-log-it_IT.mo CHANGED
Binary file
languages/wp-security-audit-log.pot CHANGED
@@ -2,10 +2,10 @@
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.6.0\n"
6
- "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/wp-security-audit-"
7
  "log\n"
8
- "POT-Creation-Date: 2015-04-16 13:28:53+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
@@ -29,27 +29,29 @@ msgstr ""
29
  msgid " Items"
30
  msgstr ""
31
 
32
- #: classes/AuditLogListView.php:64 classes/Views/AuditLog.php:85
33
  msgid "All Sites"
34
  msgstr ""
35
 
36
- #: classes/AuditLogListView.php:113 classes/Views/ToggleAlerts.php:69
 
37
  msgid "Code"
38
  msgstr ""
39
 
40
- #: classes/AuditLogListView.php:114 classes/Views/ToggleAlerts.php:70
 
41
  msgid "Type"
42
  msgstr ""
43
 
44
- #: classes/AuditLogListView.php:115
45
  msgid "Date"
46
  msgstr ""
47
 
48
- #: classes/AuditLogListView.php:116
49
  msgid "Username"
50
  msgstr ""
51
 
52
- #: classes/AuditLogListView.php:117
53
  msgid "Source IP"
54
  msgstr ""
55
 
@@ -57,39 +59,39 @@ msgstr ""
57
  msgid "Site"
58
  msgstr ""
59
 
60
- #: classes/AuditLogListView.php:122
61
  msgid "Message"
62
  msgstr ""
63
 
64
- #: classes/AuditLogListView.php:151
65
  msgid "Click to toggle."
66
  msgstr ""
67
 
68
- #: classes/AuditLogListView.php:157
69
  msgid "Unknown error code."
70
  msgstr ""
71
 
72
- #: classes/AuditLogListView.php:178 classes/AuditLogListView.php:181
73
  msgid "Unknown"
74
  msgstr ""
75
 
76
- #: classes/AuditLogListView.php:182
77
  msgid "System"
78
  msgstr ""
79
 
80
- #: classes/AuditLogListView.php:205
81
  msgid "Alert Data Inspector"
82
  msgstr ""
83
 
84
- #: classes/Sensors/Content.php:328 classes/Sensors/Content.php:336
85
  msgid "Password Protected"
86
  msgstr ""
87
 
88
- #: classes/Sensors/Content.php:330 classes/Sensors/Content.php:338
89
  msgid "Public"
90
  msgstr ""
91
 
92
- #: classes/Sensors/Content.php:332 classes/Sensors/Content.php:340
93
  msgid "Private"
94
  msgstr ""
95
 
@@ -174,25 +176,25 @@ msgstr ""
174
  msgid "and much more&hellip;"
175
  msgstr ""
176
 
177
- #: classes/Views/About.php:56 classes/Views/Help.php:79
178
- msgid "WP Password Policy Manager"
179
  msgstr ""
180
 
181
- #: classes/Views/About.php:59 classes/Views/Help.php:82
182
  msgid ""
183
- "Easily configure WordPress password policies and ensure users use strong "
184
- "passwords with our plugin WP Password Policy Manager."
185
  msgstr ""
186
 
187
- #: classes/Views/About.php:61 classes/Views/Help.php:84
188
- msgid "Download"
189
  msgstr ""
190
 
191
- #: classes/Views/About.php:65 classes/Views/Help.php:88
192
  msgid "WP Security Audit Log in your Language!"
193
  msgstr ""
194
 
195
- #: classes/Views/About.php:67 classes/Views/Help.php:90
196
  msgid ""
197
  "If you are interested in translating our plugin please drop us an email on"
198
  msgstr ""
@@ -222,20 +224,20 @@ msgid "Audit Log Viewer"
222
  msgstr ""
223
 
224
  #: classes/Views/AuditLog.php:64 classes/Views/Licensing.php:34
225
- #: classes/Views/Settings.php:88 classes/Views/ToggleAlerts.php:28
226
  msgid "You do not have sufficient permissions to access this page."
227
  msgstr ""
228
 
229
- #: classes/Views/AuditLog.php:84
230
  msgid "Please enter the number of alerts you would like to see on one page:"
231
  msgstr ""
232
 
233
- #: classes/Views/AuditLog.php:86
234
  msgid "No Results"
235
  msgstr ""
236
 
237
  #: classes/Views/Extensions.php:6
238
- msgid "WP Security Audit Log Functionality Extensions"
239
  msgstr ""
240
 
241
  #: classes/Views/Extensions.php:14
@@ -244,14 +246,15 @@ msgstr ""
244
 
245
  #: classes/Views/Extensions.php:27
246
  msgid ""
247
- "The below extensions allow you to extend the functionality of WP Security "
248
- "Audit Log plugin thus enabling you to get more benefits out of the WordPress "
249
- "security audit, such as configurable WordPress email alerts, WordPress "
250
- "security alerts search and user activity reports."
 
251
  msgstr ""
252
 
253
  #: classes/Views/Extensions.php:31
254
- msgid "WordPress Email Notifications Extension"
255
  msgstr ""
256
 
257
  #: classes/Views/Extensions.php:32
@@ -262,52 +265,68 @@ msgstr ""
262
 
263
  #: classes/Views/Extensions.php:33
264
  msgid ""
265
- "With the Notifications Extension you can easily configure monitoring rules "
266
- "so when a specific change happens on your WordPress you are alerted via "
267
- "email. For example you can configure rules to receive an email when existing "
268
- "content is changed, when a new user is created or when someone logs in to "
269
- "WordPress outside normal office hours or from an odd location."
270
  msgstr ""
271
 
272
  #: classes/Views/Extensions.php:34 classes/Views/Extensions.php:41
273
- #: classes/Views/Extensions.php:48
274
  msgid "More Information"
275
  msgstr ""
276
 
277
  #: classes/Views/Extensions.php:38
278
- msgid "Security Alerts Search Extension"
279
  msgstr ""
280
 
281
  #: classes/Views/Extensions.php:39
282
- msgid ""
283
- "Automatically Search for specific WordPress user and site activity in "
284
- "WordPress Security Audit Log."
285
  msgstr ""
286
 
287
  #: classes/Views/Extensions.php:40
288
  msgid ""
289
- "The Search Extension enables you to easily find specific WordPress activity "
290
- "in the Audit Log with free text based searches. Filters can also be used in "
291
- "conjunction with free text based searches to further narrow down and have "
292
- "more accurate search results."
293
  msgstr ""
294
 
295
  #: classes/Views/Extensions.php:45
296
- msgid "Reporting Extension"
297
  msgstr ""
298
 
299
  #: classes/Views/Extensions.php:46
300
- msgid "Generate User, Site and Other Types of Reports from the Audit Log."
 
 
301
  msgstr ""
302
 
303
  #: classes/Views/Extensions.php:47
304
  msgid ""
305
- "The Reporting Extension allows you to generate reports to keep track and "
306
- "record of the productivity, and to meet any legal and regulatory compliance "
307
- "your business need to adhere to. Unlike other reporting plugins WSAL "
308
- "Reporting Extension does not have any built-in templates that restrict you "
309
- "to specific type of reports, you can generate any type of report using all "
310
- "of the available data."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  msgstr ""
312
 
313
  #: classes/Views/Help.php:6 classes/Views/Help.php:14
@@ -345,18 +364,18 @@ msgstr ""
345
  #: classes/Views/Help.php:41
346
  msgid ""
347
  "For more detailed information about WP Security Audit Log you can visit the "
348
- "official plugin page."
349
  msgstr ""
350
 
351
  #: classes/Views/Help.php:42
352
  msgid ""
353
  "You can also visit the official list of WordPress Security Alerts for more "
354
- "information about all of the activity you can monitor with WP Security Audit "
355
- "Log."
356
  msgstr ""
357
 
358
  #: classes/Views/Help.php:44
359
- msgid "Official Plugin Page"
360
  msgstr ""
361
 
362
  #: classes/Views/Help.php:46
@@ -364,55 +383,29 @@ msgid "List of WordPress Security Alerts"
364
  msgstr ""
365
 
366
  #: classes/Views/Help.php:51
367
- msgid "Need Help Securing WordPress?"
368
  msgstr ""
369
 
370
  #: classes/Views/Help.php:53
371
- msgid "Is your WordPress website hackable?"
372
- msgstr ""
373
-
374
- #: classes/Views/Help.php:54
375
- msgid ""
376
- "If you are not sure contact our WordPress security professionals to audit "
377
- "your WordPress or to simply secure your WordPress website."
378
- msgstr ""
379
-
380
- #: classes/Views/Help.php:55
381
- msgid "Click on any of the below service buttons for more information."
382
- msgstr ""
383
-
384
- #: classes/Views/Help.php:57
385
- msgid "WordPress Security Hardening"
386
- msgstr ""
387
-
388
- #: classes/Views/Help.php:59
389
- msgid "WordPress Security Audit"
390
- msgstr ""
391
-
392
- #: classes/Views/Help.php:64
393
- msgid "WordPress Security Readings"
394
- msgstr ""
395
-
396
- #: classes/Views/Help.php:66
397
  msgid "New to WordPress security?"
398
  msgstr ""
399
 
400
- #: classes/Views/Help.php:67
401
  msgid "Do not know from where to start or which is the best services for you?"
402
  msgstr ""
403
 
404
- #: classes/Views/Help.php:68
405
  msgid ""
406
  "Visit our WordPress security blog or the WordPress Security category "
407
  "directly for more information and a number of tips and tricks about "
408
  "WordPress security."
409
  msgstr ""
410
 
411
- #: classes/Views/Help.php:70
412
  msgid "WP White Security Blog"
413
  msgstr ""
414
 
415
- #: classes/Views/Help.php:72
416
  msgid "WordPress Security Category"
417
  msgstr ""
418
 
@@ -420,12 +413,12 @@ msgstr ""
420
  msgid "Licensing"
421
  msgstr ""
422
 
423
- #: classes/Views/Licensing.php:39 classes/Views/Settings.php:93
424
  #: classes/Views/ToggleAlerts.php:43
425
  msgid "Settings have been saved."
426
  msgstr ""
427
 
428
- #: classes/Views/Licensing.php:41 classes/Views/Settings.php:95
429
  #: classes/Views/ToggleAlerts.php:45
430
  msgid "Error: "
431
  msgstr ""
@@ -442,111 +435,111 @@ msgstr ""
442
  msgid "Inactive"
443
  msgstr ""
444
 
445
- #: classes/Views/Settings.php:18 classes/Views/Settings.php:26
446
  msgid "Settings"
447
  msgstr ""
448
 
449
- #: classes/Views/Settings.php:122
450
  msgid "Security Alerts Pruning"
451
  msgstr ""
452
 
453
- #: classes/Views/Settings.php:125 classes/Views/Settings.php:133
454
  msgid "(eg: 1 month)"
455
  msgstr ""
456
 
457
- #: classes/Views/Settings.php:129
458
  msgid "None"
459
  msgstr ""
460
 
461
- #: classes/Views/Settings.php:137
462
  msgid "Delete alerts older than"
463
  msgstr ""
464
 
465
- #: classes/Views/Settings.php:145
466
  msgid "(eg: 80)"
467
  msgstr ""
468
 
469
- #: classes/Views/Settings.php:149
470
  msgid "Keep up to"
471
  msgstr ""
472
 
473
- #: classes/Views/Settings.php:154
474
  msgid "alerts"
475
  msgstr ""
476
 
477
- #: classes/Views/Settings.php:158
478
  msgid "Next Scheduled Cleanup is in "
479
  msgstr ""
480
 
481
- #: classes/Views/Settings.php:162
482
  msgid "(or %s)"
483
  msgstr ""
484
 
485
- #: classes/Views/Settings.php:163
486
  msgid "Run Manually"
487
  msgstr ""
488
 
489
- #: classes/Views/Settings.php:169
490
  msgid "Alerts Dashboard Widget"
491
  msgstr ""
492
 
493
- #: classes/Views/Settings.php:175
494
  msgid "On"
495
  msgstr ""
496
 
497
- #: classes/Views/Settings.php:180
498
  msgid "Off"
499
  msgstr ""
500
 
501
- #: classes/Views/Settings.php:185
502
  msgid "Display a dashboard widget with the latest %d security alerts."
503
  msgstr ""
504
 
505
- #: classes/Views/Settings.php:193
506
  msgid "Reverse Proxy / Firewall Options"
507
  msgstr ""
508
 
509
- #: classes/Views/Settings.php:199
510
  msgid "WordPress running behind firewall or proxy"
511
  msgstr ""
512
 
513
- #: classes/Views/Settings.php:200
514
  msgid ""
515
  "Enable this option if your WordPress is running behind a firewall or reverse "
516
  "proxy. When this option is enabled the plugin will retrieve the user's IP "
517
  "address from the proxy header."
518
  msgstr ""
519
 
520
- #: classes/Views/Settings.php:206
521
  msgid "Filter Internal IP Addresses"
522
  msgstr ""
523
 
524
- #: classes/Views/Settings.php:207
525
  msgid ""
526
  "Enable this option to filter internal IP addresses from the proxy headers."
527
  msgstr ""
528
 
529
- #: classes/Views/Settings.php:213
530
  msgid "Can View Alerts"
531
  msgstr ""
532
 
533
- #: classes/Views/Settings.php:220
534
  msgid "Users and Roles in this list can view the security alerts"
535
  msgstr ""
536
 
537
- #: classes/Views/Settings.php:235
538
  msgid "Can Manage Plugin"
539
  msgstr ""
540
 
541
- #: classes/Views/Settings.php:242
542
  msgid "Users and Roles in this list can manage the plugin settings"
543
  msgstr ""
544
 
545
- #: classes/Views/Settings.php:257
546
  msgid "Restrict Plugin Access"
547
  msgstr ""
548
 
549
- #: classes/Views/Settings.php:265
550
  msgid ""
551
  "By default all the administrators on this WordPress have access to manage "
552
  "this plugin.<br/>By enabling this option only the users specified in the two "
@@ -554,104 +547,144 @@ msgid ""
554
  "this plugin."
555
  msgstr ""
556
 
557
- #: classes/Views/Settings.php:272
558
  msgid "Refresh Audit Log Viewer"
559
  msgstr ""
560
 
561
- #: classes/Views/Settings.php:278
562
  msgid "Automatic"
563
  msgstr ""
564
 
565
- #: classes/Views/Settings.php:280
566
  msgid "Refresh Audit Log Viewer as soon as there are new alerts."
567
  msgstr ""
568
 
569
- #: classes/Views/Settings.php:284
570
  msgid "Manual"
571
  msgstr ""
572
 
573
- #: classes/Views/Settings.php:286
574
  msgid "Refresh Audit Log Viewer only when the page is reloaded."
575
  msgstr ""
576
 
577
- #: classes/Views/Settings.php:292
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
  msgid "Developer Options"
579
  msgstr ""
580
 
581
- #: classes/Views/Settings.php:300
582
  msgid ""
583
  "Only enable these options on testing, staging and development websites. "
584
  "Enabling any of the settings below on LIVE websites may cause unintended "
585
  "side-effects including degraded performance."
586
  msgstr ""
587
 
588
- #: classes/Views/Settings.php:304
589
  msgid "Data Inspector"
590
  msgstr ""
591
 
592
- #: classes/Views/Settings.php:305
593
  msgid "View data logged for each triggered alert."
594
  msgstr ""
595
 
596
- #: classes/Views/Settings.php:308
597
  msgid "PHP Errors"
598
  msgstr ""
599
 
600
- #: classes/Views/Settings.php:309
601
  msgid "Enables sensor for alerts generated from PHP."
602
  msgstr ""
603
 
604
- #: classes/Views/Settings.php:312
605
  msgid "Request Log"
606
  msgstr ""
607
 
608
- #: classes/Views/Settings.php:313
609
  msgid "Enables logging request to file."
610
  msgstr ""
611
 
612
- #: classes/Views/Settings.php:316
613
  msgid "Backtrace"
614
  msgstr ""
615
 
616
- #: classes/Views/Settings.php:317
617
  msgid "Log full backtrace for PHP-generated alerts."
618
  msgstr ""
619
 
620
- #: classes/Views/Settings.php:335
621
  msgid "Hide Plugin in Plugins Page"
622
  msgstr ""
623
 
624
- #: classes/Views/Settings.php:341
625
  msgid "Hide"
626
  msgstr ""
627
 
628
- #: classes/Views/Settings.php:345
629
  msgid ""
630
  "To manually revert this setting set the value of option wsal-hide-plugin to "
631
  "0 in the wp_options table."
632
  msgstr ""
633
 
634
- #: classes/Views/Settings.php:351
 
 
 
 
 
 
 
 
 
 
 
 
 
635
  msgid "Remove Data on Unistall"
636
  msgstr ""
637
 
638
- #: classes/Views/Settings.php:373
639
  msgid "Excluded Users"
640
  msgstr ""
641
 
642
- #: classes/Views/Settings.php:392
643
  msgid "Excluded Roles"
644
  msgstr ""
645
 
646
- #: classes/Views/Settings.php:417
647
  msgid "Excluded Custom Fields"
648
  msgstr ""
649
 
 
 
 
 
650
  #: classes/Views/ToggleAlerts.php:5 classes/Views/ToggleAlerts.php:13
651
  msgid "Enable/Disable Alerts"
652
  msgstr ""
653
 
654
- #: classes/Views/ToggleAlerts.php:71 classes/WidgetManager.php:38
655
  msgid "Description"
656
  msgstr ""
657
 
@@ -671,11 +704,11 @@ msgstr ""
671
  msgid "Latest Alerts"
672
  msgstr ""
673
 
674
- #: classes/WidgetManager.php:32
675
  msgid "No alerts found."
676
  msgstr ""
677
 
678
- #: classes/WidgetManager.php:37
679
  msgid "User"
680
  msgstr ""
681
 
@@ -1798,7 +1831,7 @@ msgid ""
1798
  "%TableNames%"
1799
  msgstr ""
1800
 
1801
- #: wp-security-audit-log.php:247
1802
  msgid ""
1803
  "You are using a version of PHP that is older than %s, which is no longer "
1804
  "supported.<br/>Contact us on <a href=\"mailto:plugins@wpwhitesecurity.com"
@@ -1810,10 +1843,11 @@ msgstr ""
1810
  msgid "WP Security Audit Log"
1811
  msgstr ""
1812
 
 
1813
  #. Plugin URI of the plugin/theme
1814
- msgid ""
1815
- "http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-"
1816
- "log/"
1817
  msgstr ""
1818
 
1819
  #. Description of the plugin/theme
@@ -1829,7 +1863,3 @@ msgstr ""
1829
  #. Author of the plugin/theme
1830
  msgid "WP White Security"
1831
  msgstr ""
1832
-
1833
- #. Author URI of the plugin/theme
1834
- msgid "http://www.wpwhitesecurity.com/"
1835
- msgstr ""
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 2.1.0\n"
6
+ "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wp-security-audit-"
7
  "log\n"
8
+ "POT-Creation-Date: 2015-09-09 06:21:38+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
29
  msgid " Items"
30
  msgstr ""
31
 
32
+ #: classes/AuditLogListView.php:64 classes/Views/AuditLog.php:86
33
  msgid "All Sites"
34
  msgstr ""
35
 
36
+ #: classes/AuditLogListView.php:113 classes/AuditLogListView.php:133
37
+ #: classes/Views/ToggleAlerts.php:69
38
  msgid "Code"
39
  msgstr ""
40
 
41
+ #: classes/AuditLogListView.php:114 classes/AuditLogListView.php:136
42
+ #: classes/Views/ToggleAlerts.php:70
43
  msgid "Type"
44
  msgstr ""
45
 
46
+ #: classes/AuditLogListView.php:115 classes/AuditLogListView.php:139
47
  msgid "Date"
48
  msgstr ""
49
 
50
+ #: classes/AuditLogListView.php:116 classes/AuditLogListView.php:142
51
  msgid "Username"
52
  msgstr ""
53
 
54
+ #: classes/AuditLogListView.php:117 classes/AuditLogListView.php:145
55
  msgid "Source IP"
56
  msgstr ""
57
 
59
  msgid "Site"
60
  msgstr ""
61
 
62
+ #: classes/AuditLogListView.php:122 classes/AuditLogListView.php:148
63
  msgid "Message"
64
  msgstr ""
65
 
66
+ #: classes/AuditLogListView.php:181
67
  msgid "Click to toggle."
68
  msgstr ""
69
 
70
+ #: classes/AuditLogListView.php:187
71
  msgid "Unknown error code."
72
  msgstr ""
73
 
74
+ #: classes/AuditLogListView.php:211 classes/AuditLogListView.php:215
75
  msgid "Unknown"
76
  msgstr ""
77
 
78
+ #: classes/AuditLogListView.php:216
79
  msgid "System"
80
  msgstr ""
81
 
82
+ #: classes/AuditLogListView.php:243
83
  msgid "Alert Data Inspector"
84
  msgstr ""
85
 
86
+ #: classes/Sensors/Content.php:373 classes/Sensors/Content.php:381
87
  msgid "Password Protected"
88
  msgstr ""
89
 
90
+ #: classes/Sensors/Content.php:375 classes/Sensors/Content.php:383
91
  msgid "Public"
92
  msgstr ""
93
 
94
+ #: classes/Sensors/Content.php:377 classes/Sensors/Content.php:385
95
  msgid "Private"
96
  msgstr ""
97
 
176
  msgid "and much more&hellip;"
177
  msgstr ""
178
 
179
+ #: classes/Views/About.php:56
180
+ msgid "Extend the Functionality & Get More Value from WP Security Audit Log"
181
  msgstr ""
182
 
183
+ #: classes/Views/About.php:59
184
  msgid ""
185
+ "Get more value out of WP Security Audit Log by extending the functionality "
186
+ "of WP Security Audit Log with the premium Add-Ons."
187
  msgstr ""
188
 
189
+ #: classes/Views/About.php:61
190
+ msgid "See Add-Ons"
191
  msgstr ""
192
 
193
+ #: classes/Views/About.php:65 classes/Views/Help.php:66
194
  msgid "WP Security Audit Log in your Language!"
195
  msgstr ""
196
 
197
+ #: classes/Views/About.php:67 classes/Views/Help.php:68
198
  msgid ""
199
  "If you are interested in translating our plugin please drop us an email on"
200
  msgstr ""
224
  msgstr ""
225
 
226
  #: classes/Views/AuditLog.php:64 classes/Views/Licensing.php:34
227
+ #: classes/Views/Settings.php:123 classes/Views/ToggleAlerts.php:28
228
  msgid "You do not have sufficient permissions to access this page."
229
  msgstr ""
230
 
231
+ #: classes/Views/AuditLog.php:85
232
  msgid "Please enter the number of alerts you would like to see on one page:"
233
  msgstr ""
234
 
235
+ #: classes/Views/AuditLog.php:87
236
  msgid "No Results"
237
  msgstr ""
238
 
239
  #: classes/Views/Extensions.php:6
240
+ msgid "WP Security Audit Log Add-Ons"
241
  msgstr ""
242
 
243
  #: classes/Views/Extensions.php:14
246
 
247
  #: classes/Views/Extensions.php:27
248
  msgid ""
249
+ "The below add-ons allow you to extend the functionality of WP Security Audit "
250
+ "Log plugin and enable you to get more benefits out of the WordPress security "
251
+ "audit, such as configurable email alerts, ability to search using free text "
252
+ "based searches & filters, and generate user activity reports to meet "
253
+ "regulatory compliance requirements."
254
  msgstr ""
255
 
256
  #: classes/Views/Extensions.php:31
257
+ msgid "Email Notifications Add-On"
258
  msgstr ""
259
 
260
  #: classes/Views/Extensions.php:32
265
 
266
  #: classes/Views/Extensions.php:33
267
  msgid ""
268
+ "With the Email Notifications Add-On you can easily configure trigger rules "
269
+ "so when a specific change happens on your WordPress you are instantly "
270
+ "alerted via email. For example you can configure rules to receive an email "
271
+ "when existing content is changed, when a new user is created or when someone "
272
+ "logs in to WordPress outside normal office hours or from an odd location."
273
  msgstr ""
274
 
275
  #: classes/Views/Extensions.php:34 classes/Views/Extensions.php:41
276
+ #: classes/Views/Extensions.php:48 classes/Views/Extensions.php:55
277
  msgid "More Information"
278
  msgstr ""
279
 
280
  #: classes/Views/Extensions.php:38
281
+ msgid "External DB Add-On"
282
  msgstr ""
283
 
284
  #: classes/Views/Extensions.php:39
285
+ msgid "Save the WordPress Audit Log in an external database."
 
 
286
  msgstr ""
287
 
288
  #: classes/Views/Extensions.php:40
289
  msgid ""
290
+ "By saving the WordPress Audit Log in an external database you improve the "
291
+ "security and performance of your WordPress websites and blogs. You also "
292
+ "ensure that your WordPress is compliant to a number of mandatory regulatory "
293
+ "compliance requirements business websites need to adhere to."
294
  msgstr ""
295
 
296
  #: classes/Views/Extensions.php:45
297
+ msgid "Search Add-On"
298
  msgstr ""
299
 
300
  #: classes/Views/Extensions.php:46
301
+ msgid ""
302
+ "Automatically Search for specific WordPress user and site activity in "
303
+ "WordPress Security Audit Log."
304
  msgstr ""
305
 
306
  #: classes/Views/Extensions.php:47
307
  msgid ""
308
+ "The Search Add-On enables you to easily find specific WordPress activity in "
309
+ "the Audit Log with free-text based searches. Filters can also be used in "
310
+ "conjunction with free-text based searches to fine tune the search and find "
311
+ "what you are looking for easily."
312
+ msgstr ""
313
+
314
+ #: classes/Views/Extensions.php:52
315
+ msgid "Reports Add-Ons"
316
+ msgstr ""
317
+
318
+ #: classes/Views/Extensions.php:53
319
+ msgid "Generate User, Site and Regulatory Compliance Reports."
320
+ msgstr ""
321
+
322
+ #: classes/Views/Extensions.php:54
323
+ msgid ""
324
+ "The Reports Add-On allows you to generate reports and keep track and record "
325
+ "of user productivity, and meet any legal and regulatory compliance your "
326
+ "business need to adhere to. Unlike other reporting plugins the Reports Add-"
327
+ "On does not have any built-in templates that restrict you to specific type "
328
+ "of reports, you can generate any type of report using all of the available "
329
+ "data."
330
  msgstr ""
331
 
332
  #: classes/Views/Help.php:6 classes/Views/Help.php:14
364
  #: classes/Views/Help.php:41
365
  msgid ""
366
  "For more detailed information about WP Security Audit Log you can visit the "
367
+ "plugin website."
368
  msgstr ""
369
 
370
  #: classes/Views/Help.php:42
371
  msgid ""
372
  "You can also visit the official list of WordPress Security Alerts for more "
373
+ "information about all of the WordPress activity and changes you can monitor "
374
+ "with WP Security Audit Log."
375
  msgstr ""
376
 
377
  #: classes/Views/Help.php:44
378
+ msgid "Plugin Website"
379
  msgstr ""
380
 
381
  #: classes/Views/Help.php:46
383
  msgstr ""
384
 
385
  #: classes/Views/Help.php:51
386
+ msgid "WordPress Security Blog"
387
  msgstr ""
388
 
389
  #: classes/Views/Help.php:53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  msgid "New to WordPress security?"
391
  msgstr ""
392
 
393
+ #: classes/Views/Help.php:54
394
  msgid "Do not know from where to start or which is the best services for you?"
395
  msgstr ""
396
 
397
+ #: classes/Views/Help.php:55
398
  msgid ""
399
  "Visit our WordPress security blog or the WordPress Security category "
400
  "directly for more information and a number of tips and tricks about "
401
  "WordPress security."
402
  msgstr ""
403
 
404
+ #: classes/Views/Help.php:57
405
  msgid "WP White Security Blog"
406
  msgstr ""
407
 
408
+ #: classes/Views/Help.php:59
409
  msgid "WordPress Security Category"
410
  msgstr ""
411
 
413
  msgid "Licensing"
414
  msgstr ""
415
 
416
+ #: classes/Views/Licensing.php:39 classes/Views/Settings.php:129
417
  #: classes/Views/ToggleAlerts.php:43
418
  msgid "Settings have been saved."
419
  msgstr ""
420
 
421
+ #: classes/Views/Licensing.php:41 classes/Views/Settings.php:132
422
  #: classes/Views/ToggleAlerts.php:45
423
  msgid "Error: "
424
  msgstr ""
435
  msgid "Inactive"
436
  msgstr ""
437
 
438
+ #: classes/Views/Settings.php:20 classes/Views/Settings.php:28
439
  msgid "Settings"
440
  msgstr ""
441
 
442
+ #: classes/Views/Settings.php:162
443
  msgid "Security Alerts Pruning"
444
  msgstr ""
445
 
446
+ #: classes/Views/Settings.php:165 classes/Views/Settings.php:173
447
  msgid "(eg: 1 month)"
448
  msgstr ""
449
 
450
+ #: classes/Views/Settings.php:169
451
  msgid "None"
452
  msgstr ""
453
 
454
+ #: classes/Views/Settings.php:177
455
  msgid "Delete alerts older than"
456
  msgstr ""
457
 
458
+ #: classes/Views/Settings.php:185
459
  msgid "(eg: 80)"
460
  msgstr ""
461
 
462
+ #: classes/Views/Settings.php:189
463
  msgid "Keep up to"
464
  msgstr ""
465
 
466
+ #: classes/Views/Settings.php:194
467
  msgid "alerts"
468
  msgstr ""
469
 
470
+ #: classes/Views/Settings.php:198
471
  msgid "Next Scheduled Cleanup is in "
472
  msgstr ""
473
 
474
+ #: classes/Views/Settings.php:202
475
  msgid "(or %s)"
476
  msgstr ""
477
 
478
+ #: classes/Views/Settings.php:203
479
  msgid "Run Manually"
480
  msgstr ""
481
 
482
+ #: classes/Views/Settings.php:209
483
  msgid "Alerts Dashboard Widget"
484
  msgstr ""
485
 
486
+ #: classes/Views/Settings.php:215
487
  msgid "On"
488
  msgstr ""
489
 
490
+ #: classes/Views/Settings.php:220
491
  msgid "Off"
492
  msgstr ""
493
 
494
+ #: classes/Views/Settings.php:225
495
  msgid "Display a dashboard widget with the latest %d security alerts."
496
  msgstr ""
497
 
498
+ #: classes/Views/Settings.php:233
499
  msgid "Reverse Proxy / Firewall Options"
500
  msgstr ""
501
 
502
+ #: classes/Views/Settings.php:239
503
  msgid "WordPress running behind firewall or proxy"
504
  msgstr ""
505
 
506
+ #: classes/Views/Settings.php:240
507
  msgid ""
508
  "Enable this option if your WordPress is running behind a firewall or reverse "
509
  "proxy. When this option is enabled the plugin will retrieve the user's IP "
510
  "address from the proxy header."
511
  msgstr ""
512
 
513
+ #: classes/Views/Settings.php:246
514
  msgid "Filter Internal IP Addresses"
515
  msgstr ""
516
 
517
+ #: classes/Views/Settings.php:247
518
  msgid ""
519
  "Enable this option to filter internal IP addresses from the proxy headers."
520
  msgstr ""
521
 
522
+ #: classes/Views/Settings.php:253
523
  msgid "Can View Alerts"
524
  msgstr ""
525
 
526
+ #: classes/Views/Settings.php:260
527
  msgid "Users and Roles in this list can view the security alerts"
528
  msgstr ""
529
 
530
+ #: classes/Views/Settings.php:275
531
  msgid "Can Manage Plugin"
532
  msgstr ""
533
 
534
+ #: classes/Views/Settings.php:282
535
  msgid "Users and Roles in this list can manage the plugin settings"
536
  msgstr ""
537
 
538
+ #: classes/Views/Settings.php:297
539
  msgid "Restrict Plugin Access"
540
  msgstr ""
541
 
542
+ #: classes/Views/Settings.php:305
543
  msgid ""
544
  "By default all the administrators on this WordPress have access to manage "
545
  "this plugin.<br/>By enabling this option only the users specified in the two "
547
  "this plugin."
548
  msgstr ""
549
 
550
+ #: classes/Views/Settings.php:312
551
  msgid "Refresh Audit Log Viewer"
552
  msgstr ""
553
 
554
+ #: classes/Views/Settings.php:318
555
  msgid "Automatic"
556
  msgstr ""
557
 
558
+ #: classes/Views/Settings.php:320
559
  msgid "Refresh Audit Log Viewer as soon as there are new alerts."
560
  msgstr ""
561
 
562
+ #: classes/Views/Settings.php:324
563
  msgid "Manual"
564
  msgstr ""
565
 
566
+ #: classes/Views/Settings.php:326
567
  msgid "Refresh Audit Log Viewer only when the page is reloaded."
568
  msgstr ""
569
 
570
+ #: classes/Views/Settings.php:332
571
+ msgid "Alerts Time Format"
572
+ msgstr ""
573
+
574
+ #: classes/Views/Settings.php:338
575
+ msgid "24 hours"
576
+ msgstr ""
577
+
578
+ #: classes/Views/Settings.php:343
579
+ msgid "AM/PM"
580
+ msgstr ""
581
+
582
+ #: classes/Views/Settings.php:350
583
+ msgid "Audit Log Columns Selection"
584
+ msgstr ""
585
+
586
+ #: classes/Views/Settings.php:361
587
+ msgid ""
588
+ "When you disable any of the above such details won’t be shown in the Audit "
589
+ "Log\r\n"
590
+ "viewer though the plugin will still record such information in the database."
591
+ msgstr ""
592
+
593
+ #: classes/Views/Settings.php:367
594
  msgid "Developer Options"
595
  msgstr ""
596
 
597
+ #: classes/Views/Settings.php:375
598
  msgid ""
599
  "Only enable these options on testing, staging and development websites. "
600
  "Enabling any of the settings below on LIVE websites may cause unintended "
601
  "side-effects including degraded performance."
602
  msgstr ""
603
 
604
+ #: classes/Views/Settings.php:379
605
  msgid "Data Inspector"
606
  msgstr ""
607
 
608
+ #: classes/Views/Settings.php:380
609
  msgid "View data logged for each triggered alert."
610
  msgstr ""
611
 
612
+ #: classes/Views/Settings.php:383
613
  msgid "PHP Errors"
614
  msgstr ""
615
 
616
+ #: classes/Views/Settings.php:384
617
  msgid "Enables sensor for alerts generated from PHP."
618
  msgstr ""
619
 
620
+ #: classes/Views/Settings.php:387
621
  msgid "Request Log"
622
  msgstr ""
623
 
624
+ #: classes/Views/Settings.php:388
625
  msgid "Enables logging request to file."
626
  msgstr ""
627
 
628
+ #: classes/Views/Settings.php:391
629
  msgid "Backtrace"
630
  msgstr ""
631
 
632
+ #: classes/Views/Settings.php:392
633
  msgid "Log full backtrace for PHP-generated alerts."
634
  msgstr ""
635
 
636
+ #: classes/Views/Settings.php:410
637
  msgid "Hide Plugin in Plugins Page"
638
  msgstr ""
639
 
640
+ #: classes/Views/Settings.php:416
641
  msgid "Hide"
642
  msgstr ""
643
 
644
+ #: classes/Views/Settings.php:420
645
  msgid ""
646
  "To manually revert this setting set the value of option wsal-hide-plugin to "
647
  "0 in the wp_options table."
648
  msgstr ""
649
 
650
+ #: classes/Views/Settings.php:426
651
+ msgid "Disable Alerts for WordPress Background Activity"
652
+ msgstr ""
653
+
654
+ #: classes/Views/Settings.php:432
655
+ msgid "Hide activity"
656
+ msgstr ""
657
+
658
+ #: classes/Views/Settings.php:436
659
+ msgid ""
660
+ "For example do not raise an alert when WordPress deletes the auto drafts."
661
+ msgstr ""
662
+
663
+ #: classes/Views/Settings.php:442
664
  msgid "Remove Data on Unistall"
665
  msgstr ""
666
 
667
+ #: classes/Views/Settings.php:465
668
  msgid "Excluded Users"
669
  msgstr ""
670
 
671
+ #: classes/Views/Settings.php:484
672
  msgid "Excluded Roles"
673
  msgstr ""
674
 
675
+ #: classes/Views/Settings.php:509
676
  msgid "Excluded Custom Fields"
677
  msgstr ""
678
 
679
+ #: classes/Views/Settings.php:534
680
+ msgid "Excluded IP Addresses"
681
+ msgstr ""
682
+
683
  #: classes/Views/ToggleAlerts.php:5 classes/Views/ToggleAlerts.php:13
684
  msgid "Enable/Disable Alerts"
685
  msgstr ""
686
 
687
+ #: classes/Views/ToggleAlerts.php:71 classes/WidgetManager.php:39
688
  msgid "Description"
689
  msgstr ""
690
 
704
  msgid "Latest Alerts"
705
  msgstr ""
706
 
707
+ #: classes/WidgetManager.php:33
708
  msgid "No alerts found."
709
  msgstr ""
710
 
711
+ #: classes/WidgetManager.php:38
712
  msgid "User"
713
  msgstr ""
714
 
1831
  "%TableNames%"
1832
  msgstr ""
1833
 
1834
+ #: wp-security-audit-log.php:249
1835
  msgid ""
1836
  "You are using a version of PHP that is older than %s, which is no longer "
1837
  "supported.<br/>Contact us on <a href=\"mailto:plugins@wpwhitesecurity.com"
1843
  msgid "WP Security Audit Log"
1844
  msgstr ""
1845
 
1846
+ #. #-#-#-#-# plugin.pot (WP Security Audit Log 2.1.0) #-#-#-#-#
1847
  #. Plugin URI of the plugin/theme
1848
+ #. #-#-#-#-# plugin.pot (WP Security Audit Log 2.1.0) #-#-#-#-#
1849
+ #. Author URI of the plugin/theme
1850
+ msgid "http://www.wpsecurityauditlog.com/"
1851
  msgstr ""
1852
 
1853
  #. Description of the plugin/theme
1863
  #. Author of the plugin/theme
1864
  msgid "WP White Security"
1865
  msgstr ""
 
 
 
 
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.2.3
10
- Stable tag: 2.0.1
11
 
12
  Keep a WordPress audit log of all users' changes and under the hood WordPress activity - Identify WordPress issues before they become security problems.
13
 
@@ -17,7 +17,7 @@ Keep an audit log of everything that is happening on your WordPress and [WordPre
17
  > <strong>Free and Premium Support</strong><br>
18
  >
19
  > WP White Security provides support for WP Security Audit Log plugin on the WordPress forums for free, though please note that it is free support hence it is not always possible to answer all questions on a timely manner, although we do try.
20
- > Personalized premium support is available via email to anyone who purchases any of the [Premium Add-Ons](http://www.wpsecurityauditlog.com/plugin-extensions/), such as the [Email Notifications](http://www.wpsecurityauditlog.com/extensions/wordpress-email-notifications-add-on/), [Search](http://www.wpsecurityauditlog.com/extensions/search-add-on-for-wordpress-security-audit-log/) and [Reports](http://www.wpsecurityauditlog.com/extensions/compliance-reports-add-on-for-wordpress/) Add-Ons.
21
 
22
  = Keep A WordPress Security Audit Log & Identify WordPress Security Issues =
23
  WP Security Audit Log keeps a log of everything happening on your WordPress blog or website and WordPress multisite network. By using WP Security Audit Log security plugin it is very easy to track suspicious user activity before it becomes a problem or a security issue. A security alert is generated by the plugin when:
@@ -65,6 +65,11 @@ Use the premium [Email Notifications Add-On](http://www.wpsecurityauditlog.com/e
65
 
66
  It is virtually impossible to find specific WordPress activity by manually browsing through thousands of WordPress security alerts. Now you can use the premium [Search Add-On](http://www.wpsecurityauditlog.com/extensions/search-add-on-for-wordpress-security-audit-log/) to do free text based searches in the WordPress audit log, allowing you to easily pin point specific WordPress user, site, plugin, theme and other activity. The Search extension also has a number of built-in filters that you can use to fine tune your search results, hence allowing you to find the WordPress security alert you are looking for easily and quickly.
67
 
 
 
 
 
 
68
  = Generate HTML and CSV WordPress Reports =
69
  <strong>Generate WordPress activity reports to ensure users' productivity and meet any legal and regulatory compliance requirements your business needs to adhere to.</strong>
70
 
@@ -110,6 +115,7 @@ WP Security Audit Log plugin also has a number of features that make WordPress a
110
  * [Pagely](https://pagely.com/blog/2015/01/log-wordpress-dashboard-activity-improved-security-auditing/)
111
  * [Design Wall](http://www.designwall.com/blog/10-wordpress-multisite-plugins-you-shouldnt-live-without/)
112
  * [WPLift](http://wplift.com/wordpress-event-tracking)
 
113
  * [BlogVault](https://blogvault.net/wp-security-audit-log-plugin-review/)
114
  * [MyWPExpert](http://www.mywpexpert.com/wp-security-audit-log/)
115
  * [Shout Me Loud](http://www.shoutmeloud.com/how-to-monitor-user-activities-wordpress-dashboard.html)
@@ -162,12 +168,18 @@ You can use the premium add-on [Search Add-On](http://www.wpsecurityauditlog.com
162
  = Can I generate reports from the WordPress security audit log? =
163
  Yes it is possible to do so with the premium [Reports Add-On](http://www.wpsecurityauditlog.com/extensions/compliance-reports-add-on-for-wordpress/). This plugin extension allows you to generate any type of WordPress report using any type of data source. Reports can be generated in HTML and CSV format.
164
 
 
 
 
165
  = Can I exclude users or roles from being monitored? =
166
  Yes it is possible to exclude both users and roles from being monitored. To exclude a user or a role specify it in the Excluded Objects section in the plugin's settings node.
167
 
168
  = Can I exclude custom fields from being monitored? =
169
  Yes it is possible to exclude custom fields from being monitored. To exclude a custom field you can specify it in the Excluded Objects section in the plugin's settings node, else you can click the option Exclude Custom Field from Monitoring from the alert itself.
170
 
 
 
 
171
  == Screenshots ==
172
 
173
  1. The Audit Log Viewer from where the WordPress administrator can see all the security events generated by WP Security Audit Log WordPress plugin.
@@ -180,6 +192,22 @@ Yes it is possible to exclude custom fields from being monitored. To exclude a c
180
 
181
  == Changelog ==
182
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  = 2.0.1 (2015-08-05) =
184
  * **Minor Change**
185
  * Launched a new [WP Security Audit Log website](http://www.wpsecurityauditlog.com) and updated all relevant links.
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.3
10
+ Stable tag: 2.1.0
11
 
12
  Keep a WordPress audit log of all users' changes and under the hood WordPress activity - Identify WordPress issues before they become security problems.
13
 
17
  > <strong>Free and Premium Support</strong><br>
18
  >
19
  > WP White Security provides support for WP Security Audit Log plugin on the WordPress forums for free, though please note that it is free support hence it is not always possible to answer all questions on a timely manner, although we do try.
20
+ > Personalized premium support is available via email to anyone who purchases any of the [Premium Add-Ons](http://www.wpsecurityauditlog.com/plugin-extensions/), such as the [Email Notifications](http://www.wpsecurityauditlog.com/extensions/wordpress-email-notifications-add-on/), [Search](http://www.wpsecurityauditlog.com/extensions/search-add-on-for-wordpress-security-audit-log/), [External Database](http://www.wpsecurityauditlog.com/extensions/external-database-for-wp-security-audit-log/) and [Reports](http://www.wpsecurityauditlog.com/extensions/compliance-reports-add-on-for-wordpress/) Add-Ons.
21
 
22
  = Keep A WordPress Security Audit Log & Identify WordPress Security Issues =
23
  WP Security Audit Log keeps a log of everything happening on your WordPress blog or website and WordPress multisite network. By using WP Security Audit Log security plugin it is very easy to track suspicious user activity before it becomes a problem or a security issue. A security alert is generated by the plugin when:
65
 
66
  It is virtually impossible to find specific WordPress activity by manually browsing through thousands of WordPress security alerts. Now you can use the premium [Search Add-On](http://www.wpsecurityauditlog.com/extensions/search-add-on-for-wordpress-security-audit-log/) to do free text based searches in the WordPress audit log, allowing you to easily pin point specific WordPress user, site, plugin, theme and other activity. The Search extension also has a number of built-in filters that you can use to fine tune your search results, hence allowing you to find the WordPress security alert you are looking for easily and quickly.
67
 
68
+ = Improve the Security by Storing the Audit Log in an External Database =
69
+ <strong>Store the WordPress Audit Log in an external database to improve the security & Performance of your WordPress websites.</strong>
70
+
71
+ By storing the WordPress Audit Log in an external database with the [External DB Add-on](http://www.wpsecurityauditlog.com/extensions/external-database-for-wp-security-audit-log/) you improve the security and perforamnce of your WordPress websites and blogs. The WordPress Audit Log contains a record of everything that has happened on your WordPress hence when stored on an external database you ensure such records are not tempered with even in case the website is hacked. You also ensure that your business WordPress website is compliant to today's strict regulatory compliance requirements.
72
+
73
  = Generate HTML and CSV WordPress Reports =
74
  <strong>Generate WordPress activity reports to ensure users' productivity and meet any legal and regulatory compliance requirements your business needs to adhere to.</strong>
75
 
115
  * [Pagely](https://pagely.com/blog/2015/01/log-wordpress-dashboard-activity-improved-security-auditing/)
116
  * [Design Wall](http://www.designwall.com/blog/10-wordpress-multisite-plugins-you-shouldnt-live-without/)
117
  * [WPLift](http://wplift.com/wordpress-event-tracking)
118
+ * [Tourqe News](http://torquemag.io/5-awesome-wordpress-plugins-you-may-not-have-heard-of/)
119
  * [BlogVault](https://blogvault.net/wp-security-audit-log-plugin-review/)
120
  * [MyWPExpert](http://www.mywpexpert.com/wp-security-audit-log/)
121
  * [Shout Me Loud](http://www.shoutmeloud.com/how-to-monitor-user-activities-wordpress-dashboard.html)
168
  = Can I generate reports from the WordPress security audit log? =
169
  Yes it is possible to do so with the premium [Reports Add-On](http://www.wpsecurityauditlog.com/extensions/compliance-reports-add-on-for-wordpress/). This plugin extension allows you to generate any type of WordPress report using any type of data source. Reports can be generated in HTML and CSV format.
170
 
171
+ = Can I store the WordPress Audit Log in an external database (not in the WordPress database? =
172
+ Yes you can easily do so with the premium [External DB Add-on](http://www.wpsecurityauditlog.com/extensions/external-database-for-wp-security-audit-log/).
173
+
174
  = Can I exclude users or roles from being monitored? =
175
  Yes it is possible to exclude both users and roles from being monitored. To exclude a user or a role specify it in the Excluded Objects section in the plugin's settings node.
176
 
177
  = Can I exclude custom fields from being monitored? =
178
  Yes it is possible to exclude custom fields from being monitored. To exclude a custom field you can specify it in the Excluded Objects section in the plugin's settings node, else you can click the option Exclude Custom Field from Monitoring from the alert itself.
179
 
180
+ = Can I exclude an IP address from being monitoring? =
181
+ Yes. To exclude an IP address you can specify it in the Excluded Objects sections in the plugin's settings node.
182
+
183
  == Screenshots ==
184
 
185
  1. The Audit Log Viewer from where the WordPress administrator can see all the security events generated by WP Security Audit Log WordPress plugin.
192
 
193
  == Changelog ==
194
 
195
+ = 2.1.0 (2015-09-09) =
196
+ * **New Features**
197
+ * Support for the [External DB Add-on](http://www.wpsecurityauditlog.com/extensions/external-database-for-wp-security-audit-log/).
198
+ * Integration with WhatIsMyIPAddress.com (Click an IP addresses in Audit Log viewer to get all information about it).
199
+ * Settings to Incude or exclude specific columns from the Audit Log viewer.
200
+ * Ability to exclude an IP address from monitoring
201
+ * New option to disable the reporting of WordPress background tasks (such as deletion of auto draft posts)
202
+
203
+ * **Bug Fixes**
204
+ * Fixed a problem when trying to customize a widget via the theme customizer [support ticket](https://wordpress.org/support/topic/customizer-issues?replies=2).
205
+ * Handling an error that was generated when someone logged in to a WordPress via social media channels.
206
+ * Fixed: incorrect alert generated when a widget is moved from the bottom of a container to another.
207
+ * Fixed: incorrect alert generated when a custom filed is deleted from a page.
208
+ * Fixed an issue where post related actions were not reported for users with author and contributor roles.
209
+ * Fixed an issue where in a specific scenario the settings in the options tabel were duplicate.
210
+
211
  = 2.0.1 (2015-08-05) =
212
  * **Minor Change**
213
  * Launched a new [WP Security Audit Log website](http://www.wpsecurityauditlog.com) and updated all relevant links.
wp-security-audit-log.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: WP Security Audit Log
4
  Plugin URI: http://www.wpsecurityauditlog.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 Security Audit 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: 2.0.1
8
  Text Domain: wp-security-audit-log
9
  Author URI: http://www.wpsecurityauditlog.com/
10
  License: GPL2
@@ -542,10 +542,10 @@ class WpSecurityAuditLog {
542
  unset($this->_cleanup_hooks[$pos]);
543
  }
544
 
545
- public static function getConnector()
546
  {
547
  require_once('classes/Connector/ConnectorFactory.php');
548
- return WSAL_Connector_ConnectorFactory::getConnector();
549
  }
550
 
551
  /**
4
  Plugin URI: http://www.wpsecurityauditlog.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 Security Audit 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: 2.1.0
8
  Text Domain: wp-security-audit-log
9
  Author URI: http://www.wpsecurityauditlog.com/
10
  License: GPL2
542
  unset($this->_cleanup_hooks[$pos]);
543
  }
544
 
545
+ public static function getConnector($config = null)
546
  {
547
  require_once('classes/Connector/ConnectorFactory.php');
548
+ return WSAL_Connector_ConnectorFactory::getConnector($config);
549
  }
550
 
551
  /**