Version Description
This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.
=
Download this release
Release Info
Developer | yorman |
Plugin | Sucuri Security – Auditing, Malware Scanner and Security Hardening |
Version | 1.8.7 |
Comparing to | |
See all releases |
Code changes from version 1.8.6 to 1.8.7
- inc/css/styles.css +4 -3
- inc/tpl/auditlogs.html.tpl +38 -18
- inc/tpl/lastlogins-loggedin.snippet.tpl +1 -1
- inc/tpl/notification-simple.html.tpl +1 -1
- inc/tpl/settings-apiservice-timeout.html.tpl +0 -21
- inc/tpl/settings-general-commentmonitor.html.tpl +0 -18
- inc/tpl/{settings-general-cronjobs.html.tpl → settings-scanner-cronjobs.html.tpl} +7 -1
- inc/tpl/{settings-general-cronjobs.snippet.tpl → settings-scanner-cronjobs.snippet.tpl} +1 -1
- inc/tpl/settings-scanner-options.html.tpl +0 -24
- inc/tpl/settings.html.tpl +1 -7
- languages/sucuri-scanner-en_US.mo +0 -0
- languages/sucuri-scanner-en_US.po +11 -26
- languages/sucuri-scanner-es_ES.mo +0 -0
- languages/sucuri-scanner-es_ES.po +11 -26
- readme.txt +14 -2
- src/api.lib.php +153 -201
- src/auditlogs.lib.php +40 -28
- src/cache.lib.php +82 -42
- src/event.lib.php +109 -58
- src/fileinfo.lib.php +7 -2
- src/firewall.lib.php +3 -1
- src/globals.php +26 -3
- src/hook.lib.php +5 -45
- src/integrity.lib.php +45 -36
- src/interface.lib.php +23 -9
- src/lastlogins-loggedin.php +1 -1
- src/lastlogins.php +2 -4
- src/option.lib.php +0 -3
- src/pagehandler.php +2 -5
- src/settings-apiservice.php +0 -34
- src/settings-general.php +1 -160
- src/settings-scanner.php +98 -34
- src/sitecheck.lib.php +27 -30
- src/sucuriscan.lib.php +56 -0
- sucuri.php +4 -4
inc/css/styles.css
CHANGED
@@ -753,9 +753,6 @@ body.sucuri-security_page_sucuriscan_hardening {
|
|
753 |
.sucuriscan-tag-blue {
|
754 |
background-color: #3922f2;
|
755 |
}
|
756 |
-
.sucuriscan-auditlog-response {
|
757 |
-
margin-bottom: 30px;
|
758 |
-
}
|
759 |
.sucuriscan-auditlog-date {
|
760 |
color: #808080;
|
761 |
padding: 30px 0;
|
@@ -816,6 +813,10 @@ body.sucuri-security_page_sucuriscan_hardening {
|
|
816 |
line-height: 32px;
|
817 |
margin-left: 10px;
|
818 |
}
|
|
|
|
|
|
|
|
|
819 |
.sucuriscan-hardening-option {
|
820 |
margin-bottom: 0;
|
821 |
}
|
753 |
.sucuriscan-tag-blue {
|
754 |
background-color: #3922f2;
|
755 |
}
|
|
|
|
|
|
|
756 |
.sucuriscan-auditlog-date {
|
757 |
color: #808080;
|
758 |
padding: 30px 0;
|
813 |
line-height: 32px;
|
814 |
margin-left: 10px;
|
815 |
}
|
816 |
+
.sucuriscan-pagination-panel,
|
817 |
+
.sucuriscan-auditlog-footer {
|
818 |
+
margin-top: 30px;
|
819 |
+
}
|
820 |
.sucuriscan-hardening-option {
|
821 |
margin-bottom: 0;
|
822 |
}
|
inc/tpl/auditlogs.html.tpl
CHANGED
@@ -3,6 +3,18 @@
|
|
3 |
/* global jQuery */
|
4 |
/* jshint camelcase:false */
|
5 |
jQuery(function ($) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
var sucuriscanLoadAuditLogs = function (page, reset) {
|
7 |
var url = '%%SUCURI.AjaxURL.Dashboard%%';
|
8 |
|
@@ -14,7 +26,10 @@ jQuery(function ($) {
|
|
14 |
$('.sucuriscan-auditlog-response').html('<em>@@SUCURI.Loading@@</em>');
|
15 |
}
|
16 |
|
17 |
-
$('.sucuriscan-
|
|
|
|
|
|
|
18 |
|
19 |
$.post(url, {
|
20 |
action: 'sucuriscan_ajax',
|
@@ -23,14 +38,16 @@ jQuery(function ($) {
|
|
23 |
}, function (data) {
|
24 |
$('.sucuriscan-pagination-loading').html('');
|
25 |
|
|
|
|
|
|
|
|
|
|
|
26 |
if (data.content !== undefined) {
|
27 |
$('.sucuriscan-auditlog-response').html(data.content);
|
28 |
|
29 |
-
if (data.selfhosting) {
|
30 |
-
$('#sucuriscan-auditlog-selfhosting').removeClass('sucuriscan-hidden');
|
31 |
-
}
|
32 |
-
|
33 |
if (data.pagination !== '') {
|
|
|
34 |
$('.sucuriscan-auditlog-table .sucuriscan-pagination').html(data.pagination);
|
35 |
}
|
36 |
} else if (typeof data === 'object') {
|
@@ -54,14 +71,14 @@ jQuery(function ($) {
|
|
54 |
sucuriscanLoadAuditLogs($(this).attr('data-page'));
|
55 |
});
|
56 |
|
57 |
-
$('.sucuriscan-auditlog-table').on('click', '.sucuriscan-
|
58 |
event.preventDefault();
|
|
|
59 |
$.post('%%SUCURI.AjaxURL.Dashboard%%', {
|
60 |
action: 'sucuriscan_ajax',
|
61 |
sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
|
62 |
-
form_action: '
|
63 |
-
}, function (
|
64 |
-
console.log(data);
|
65 |
sucuriscanLoadAuditLogs(0, true);
|
66 |
});
|
67 |
});
|
@@ -69,19 +86,11 @@ jQuery(function ($) {
|
|
69 |
</script>
|
70 |
|
71 |
<div class="sucuriscan-auditlog-table">
|
72 |
-
<div id="sucuriscan-auditlog-selfhosting" class="sucuriscan-inline-alert-info sucuriscan-hidden">
|
73 |
-
<p>@@SUCURI.SelfHostingFallback@@</p>
|
74 |
-
</div>
|
75 |
-
|
76 |
<div class="sucuriscan-auditlog-response">
|
77 |
<em>@@SUCURI.Loading@@</em>
|
78 |
</div>
|
79 |
|
80 |
-
<div>
|
81 |
-
<small>@@SUCURI.AuditLogsCache@@ — <a href="#" class="sucuriscan-reset-auditlogs">@@SUCURI.Refresh@@</a></small>
|
82 |
-
</div>
|
83 |
-
|
84 |
-
<div class="sucuriscan-clearfix">
|
85 |
<ul class="sucuriscan-pull-left sucuriscan-pagination">
|
86 |
<!-- Populated via JavaScript -->
|
87 |
</ul>
|
@@ -90,4 +99,15 @@ jQuery(function ($) {
|
|
90 |
<!-- Populated via JavaScript -->
|
91 |
</div>
|
92 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
</div>
|
3 |
/* global jQuery */
|
4 |
/* jshint camelcase:false */
|
5 |
jQuery(function ($) {
|
6 |
+
var writeQueueSize = function (queueSize)
|
7 |
+
{
|
8 |
+
if (queueSize === 0) {
|
9 |
+
$('.sucuriscan-auditlogs-sendlogs-response').html('');
|
10 |
+
$('.sucuriscan-sendlogs-panel').addClass('sucuriscan-hidden');
|
11 |
+
} else {
|
12 |
+
var msg = '\x20@@SUCURI.AuditLogsQueue@@\x20—\x20';
|
13 |
+
$('.sucuriscan-auditlogs-sendlogs-response').html((queueSize).toString() + msg);
|
14 |
+
$('.sucuriscan-sendlogs-panel').removeClass('sucuriscan-hidden');
|
15 |
+
}
|
16 |
+
};
|
17 |
+
|
18 |
var sucuriscanLoadAuditLogs = function (page, reset) {
|
19 |
var url = '%%SUCURI.AjaxURL.Dashboard%%';
|
20 |
|
26 |
$('.sucuriscan-auditlog-response').html('<em>@@SUCURI.Loading@@</em>');
|
27 |
}
|
28 |
|
29 |
+
$('.sucuriscan-auditlog-status').html('');
|
30 |
+
$('.sucuriscan-pagination-loading').html('');
|
31 |
+
$('.sucuriscan-pagination-panel').addClass('sucuriscan-hidden');
|
32 |
+
$('.sucuriscan-auditlog-footer').addClass('sucuriscan-hidden');
|
33 |
|
34 |
$.post(url, {
|
35 |
action: 'sucuriscan_ajax',
|
38 |
}, function (data) {
|
39 |
$('.sucuriscan-pagination-loading').html('');
|
40 |
|
41 |
+
writeQueueSize(data.queueSize);
|
42 |
+
|
43 |
+
$('.sucuriscan-auditlog-status').html(data.status);
|
44 |
+
$('.sucuriscan-auditlog-footer').removeClass('sucuriscan-hidden');
|
45 |
+
|
46 |
if (data.content !== undefined) {
|
47 |
$('.sucuriscan-auditlog-response').html(data.content);
|
48 |
|
|
|
|
|
|
|
|
|
49 |
if (data.pagination !== '') {
|
50 |
+
$('.sucuriscan-pagination-panel').removeClass('sucuriscan-hidden');
|
51 |
$('.sucuriscan-auditlog-table .sucuriscan-pagination').html(data.pagination);
|
52 |
}
|
53 |
} else if (typeof data === 'object') {
|
71 |
sucuriscanLoadAuditLogs($(this).attr('data-page'));
|
72 |
});
|
73 |
|
74 |
+
$('.sucuriscan-auditlog-table').on('click', '.sucuriscan-auditlogs-sendlogs', function (event) {
|
75 |
event.preventDefault();
|
76 |
+
$('.sucuriscan-auditlogs-sendlogs-response').html('@@SUCURI.Loading@@');
|
77 |
$.post('%%SUCURI.AjaxURL.Dashboard%%', {
|
78 |
action: 'sucuriscan_ajax',
|
79 |
sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
|
80 |
+
form_action: 'auditlogs_send_logs',
|
81 |
+
}, function () {
|
|
|
82 |
sucuriscanLoadAuditLogs(0, true);
|
83 |
});
|
84 |
});
|
86 |
</script>
|
87 |
|
88 |
<div class="sucuriscan-auditlog-table">
|
|
|
|
|
|
|
|
|
89 |
<div class="sucuriscan-auditlog-response">
|
90 |
<em>@@SUCURI.Loading@@</em>
|
91 |
</div>
|
92 |
|
93 |
+
<div class="sucuriscan-clearfix sucuriscan-pagination-panel">
|
|
|
|
|
|
|
|
|
94 |
<ul class="sucuriscan-pull-left sucuriscan-pagination">
|
95 |
<!-- Populated via JavaScript -->
|
96 |
</ul>
|
99 |
<!-- Populated via JavaScript -->
|
100 |
</div>
|
101 |
</div>
|
102 |
+
|
103 |
+
<div class="sucuriscan-clearfix sucuriscan-auditlog-footer">
|
104 |
+
<div class="sucuriscan-pull-left sucuriscan-hidden sucuriscan-sendlogs-panel">
|
105 |
+
<small class="sucuriscan-auditlogs-sendlogs-response"></small>
|
106 |
+
<small><a href="#" class="sucuriscan-auditlogs-sendlogs">@@SUCURI.SendLogs@@</a></small>
|
107 |
+
</div>
|
108 |
+
|
109 |
+
<div class="sucuriscan-pull-right">
|
110 |
+
<small class="sucuriscan-auditlog-status"></small>
|
111 |
+
</div>
|
112 |
+
</div>
|
113 |
</div>
|
inc/tpl/lastlogins-loggedin.snippet.tpl
CHANGED
@@ -8,7 +8,7 @@
|
|
8 |
|
9 |
<td class="sucuriscan-monospace">%%SUCURI.LoggedInUsers.Registered%%</td>
|
10 |
|
11 |
-
<td class="sucuriscan-monospace">%%SUCURI.LoggedInUsers.
|
12 |
|
13 |
<td><a href="%%SUCURI.LoggedInUsers.UserURL%%" target="_blank">@@SUCURI.Edit@@</a></td>
|
14 |
</tr>
|
8 |
|
9 |
<td class="sucuriscan-monospace">%%SUCURI.LoggedInUsers.Registered%%</td>
|
10 |
|
11 |
+
<td class="sucuriscan-monospace">%%SUCURI.LoggedInUsers.RemoteAddr%%</td>
|
12 |
|
13 |
<td><a href="%%SUCURI.LoggedInUsers.UserURL%%" target="_blank">@@SUCURI.Edit@@</a></td>
|
14 |
</tr>
|
inc/tpl/notification-simple.html.tpl
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
|
2 |
@@SUCURI.Event@@: %%SUCURI.Subject%%
|
3 |
@@SUCURI.Website@@: http://%%SUCURI.Website%%
|
4 |
-
@@SUCURI.
|
5 |
@@SUCURI.Datetime@@: %%SUCURI.Time%%
|
6 |
%%SUCURI.User%%
|
7 |
|
1 |
|
2 |
@@SUCURI.Event@@: %%SUCURI.Subject%%
|
3 |
@@SUCURI.Website@@: http://%%SUCURI.Website%%
|
4 |
+
@@SUCURI.RemoteAddr@@: %%SUCURI.RemoteAddress%%
|
5 |
@@SUCURI.Datetime@@: %%SUCURI.Time%%
|
6 |
%%SUCURI.User%%
|
7 |
|
inc/tpl/settings-apiservice-timeout.html.tpl
DELETED
@@ -1,21 +0,0 @@
|
|
1 |
-
|
2 |
-
<div class="sucuriscan-panel">
|
3 |
-
<h3 class="sucuriscan-title">@@SUCURI.APITimeout@@</h3>
|
4 |
-
|
5 |
-
<div class="inside">
|
6 |
-
<p>@@SUCURI.APITimeoutInfo@@</p>
|
7 |
-
|
8 |
-
<div class="sucuriscan-hstatus sucuriscan-hstatus-2">
|
9 |
-
<span>@@SUCURI.APITimeoutValue@@</span>
|
10 |
-
</div>
|
11 |
-
|
12 |
-
<form action="%%SUCURI.URL.Settings%%#apiservice" method="post">
|
13 |
-
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
14 |
-
<fieldset class="sucuriscan-clearfix">
|
15 |
-
<label>@@SUCURI.APITimeoutLabel@@</label>
|
16 |
-
<input type="text" name="sucuriscan_request_timeout" />
|
17 |
-
<button type="submit" class="button button-primary">@@SUCURI.Submit@@</button>
|
18 |
-
</fieldset>
|
19 |
-
</form>
|
20 |
-
</div>
|
21 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/tpl/settings-general-commentmonitor.html.tpl
DELETED
@@ -1,18 +0,0 @@
|
|
1 |
-
|
2 |
-
<div class="sucuriscan-panel">
|
3 |
-
<h3 class="sucuriscan-title">@@SUCURI.CommentMonitor@@</h3>
|
4 |
-
|
5 |
-
<div class="inside">
|
6 |
-
<p>@@SUCURI.CommentMonitorInfo@@</p>
|
7 |
-
|
8 |
-
<div class="sucuriscan-hstatus sucuriscan-hstatus-2">
|
9 |
-
<span>@@SUCURI.CommentMonitor@@ — %%SUCURI.CommentMonitorStatus%%</span>
|
10 |
-
|
11 |
-
<form action="%%SUCURI.URL.Settings%%" method="post">
|
12 |
-
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
13 |
-
<input type="hidden" name="sucuriscan_comment_monitor" value="%%SUCURI.CommentMonitorSwitchValue%%" />
|
14 |
-
<button type="submit" class="button button-primary">%%SUCURI.CommentMonitorSwitchText%%</button>
|
15 |
-
</form>
|
16 |
-
</div>
|
17 |
-
</div>
|
18 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/tpl/{settings-general-cronjobs.html.tpl → settings-scanner-cronjobs.html.tpl}
RENAMED
@@ -3,9 +3,15 @@
|
|
3 |
<h3 class="sucuriscan-title">@@SUCURI.Cronjobs@@</h3>
|
4 |
|
5 |
<div class="inside">
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
<p>@@SUCURI.CronjobsInfo@@</p>
|
7 |
|
8 |
-
<form action="%%SUCURI.URL.Settings%%#
|
9 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
10 |
|
11 |
<table class="wp-list-table widefat sucuriscan-table sucuriscan-wpcron-list">
|
3 |
<h3 class="sucuriscan-title">@@SUCURI.Cronjobs@@</h3>
|
4 |
|
5 |
<div class="inside">
|
6 |
+
<p>@@SUCURI.ScannerDescription@@</p>
|
7 |
+
|
8 |
+
<div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.NoSPL.Visibility%%">
|
9 |
+
<p>@@SUCURI.ScannerWithoutSPL@@</p>
|
10 |
+
</div>
|
11 |
+
|
12 |
<p>@@SUCURI.CronjobsInfo@@</p>
|
13 |
|
14 |
+
<form action="%%SUCURI.URL.Settings%%#scanner" method="post">
|
15 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
16 |
|
17 |
<table class="wp-list-table widefat sucuriscan-table sucuriscan-wpcron-list">
|
inc/tpl/{settings-general-cronjobs.snippet.tpl → settings-scanner-cronjobs.snippet.tpl}
RENAMED
@@ -8,7 +8,7 @@
|
|
8 |
|
9 |
<td>%%SUCURI.Cronjob.Schedule%%</td>
|
10 |
|
11 |
-
<td>%%SUCURI.Cronjob.NextTime
|
12 |
|
13 |
<td>%%SUCURI.Cronjob.Arguments%%</td>
|
14 |
</tr>
|
8 |
|
9 |
<td>%%SUCURI.Cronjob.Schedule%%</td>
|
10 |
|
11 |
+
<td>%%SUCURI.Cronjob.NextTime%% <em>(%%SUCURI.Cronjob.NextTimeHuman%%)</em></td>
|
12 |
|
13 |
<td>%%SUCURI.Cronjob.Arguments%%</td>
|
14 |
</tr>
|
inc/tpl/settings-scanner-options.html.tpl
DELETED
@@ -1,24 +0,0 @@
|
|
1 |
-
|
2 |
-
<div class="sucuriscan-panel">
|
3 |
-
<h3 class="sucuriscan-title">@@SUCURI.ScannerTitle@@</h3>
|
4 |
-
|
5 |
-
<div class="inside">
|
6 |
-
<p>@@SUCURI.ScannerDescription@@</p>
|
7 |
-
|
8 |
-
<div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.NoSPL.Visibility%%">
|
9 |
-
<p>@@SUCURI.ScannerWithoutSPL@@</p>
|
10 |
-
</div>
|
11 |
-
|
12 |
-
<form action="%%SUCURI.URL.Settings%%#scanner" method="post">
|
13 |
-
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
14 |
-
|
15 |
-
<fieldset class="sucuriscan-clearfix">
|
16 |
-
<label>@@SUCURI.ScannerFrequency@@</label>
|
17 |
-
<select name="sucuriscan_scan_frequency">
|
18 |
-
%%%SUCURI.ScanningFrequencyOptions%%%
|
19 |
-
</select>
|
20 |
-
<button type="submit" class="button button-primary">@@SUCURI.Submit@@</button>
|
21 |
-
</fieldset>
|
22 |
-
</form>
|
23 |
-
</div>
|
24 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/tpl/settings.html.tpl
CHANGED
@@ -18,14 +18,10 @@
|
|
18 |
|
19 |
%%%SUCURI.Settings.General.SelfHosting%%%
|
20 |
|
21 |
-
%%%SUCURI.Settings.General.Cronjobs%%%
|
22 |
-
|
23 |
%%%SUCURI.Settings.General.ReverseProxy%%%
|
24 |
|
25 |
%%%SUCURI.Settings.General.IPDiscoverer%%%
|
26 |
|
27 |
-
%%%SUCURI.Settings.General.CommentMonitor%%%
|
28 |
-
|
29 |
%%%SUCURI.Settings.General.AuditLogStats%%%
|
30 |
|
31 |
%%%SUCURI.Settings.General.ImportExport%%%
|
@@ -34,7 +30,7 @@
|
|
34 |
</div>
|
35 |
|
36 |
<div id="sucuriscan-tabs-scanner">
|
37 |
-
%%%SUCURI.Settings.Scanner.
|
38 |
|
39 |
%%%SUCURI.Settings.Scanner.IntegrityDiffUtility%%%
|
40 |
|
@@ -106,8 +102,6 @@
|
|
106 |
<div id="sucuriscan-tabs-apiservice">
|
107 |
%%%SUCURI.Settings.APIService.Status%%%
|
108 |
|
109 |
-
%%%SUCURI.Settings.APIService.Timeout%%%
|
110 |
-
|
111 |
%%%SUCURI.Settings.APIService.Proxy%%%
|
112 |
</div>
|
113 |
|
18 |
|
19 |
%%%SUCURI.Settings.General.SelfHosting%%%
|
20 |
|
|
|
|
|
21 |
%%%SUCURI.Settings.General.ReverseProxy%%%
|
22 |
|
23 |
%%%SUCURI.Settings.General.IPDiscoverer%%%
|
24 |
|
|
|
|
|
25 |
%%%SUCURI.Settings.General.AuditLogStats%%%
|
26 |
|
27 |
%%%SUCURI.Settings.General.ImportExport%%%
|
30 |
</div>
|
31 |
|
32 |
<div id="sucuriscan-tabs-scanner">
|
33 |
+
%%%SUCURI.Settings.Scanner.Cronjobs%%%
|
34 |
|
35 |
%%%SUCURI.Settings.Scanner.IntegrityDiffUtility%%%
|
36 |
|
102 |
<div id="sucuriscan-tabs-apiservice">
|
103 |
%%%SUCURI.Settings.APIService.Status%%%
|
104 |
|
|
|
|
|
105 |
%%%SUCURI.Settings.APIService.Proxy%%%
|
106 |
</div>
|
107 |
|
languages/sucuri-scanner-en_US.mo
CHANGED
Binary file
|
languages/sucuri-scanner-en_US.po
CHANGED
@@ -194,6 +194,15 @@ msgstr "This data is cached for %%SUCURI.AuditLogs.Lifetime%% seconds"
|
|
194 |
msgid "Refresh"
|
195 |
msgstr "Refresh"
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
msgid "UnsupportedWordPress"
|
198 |
msgstr "WordPress version is not supported."
|
199 |
|
@@ -764,12 +773,6 @@ msgstr "The post-type is invalid or it may be already ignored."
|
|
764 |
msgid "APIServiceChanged"
|
765 |
msgstr "The status of the API service has been changed"
|
766 |
|
767 |
-
msgid "HTTPTimeoutChange"
|
768 |
-
msgstr "The timeout for the HTTP requests has been changed"
|
769 |
-
|
770 |
-
msgid "HTTPTimeoutFailure"
|
771 |
-
msgstr "API request timeout in seconds is too high."
|
772 |
-
|
773 |
msgid "PluginResetSuccess"
|
774 |
msgstr "Local security logs, hardening and settings were deleted"
|
775 |
|
@@ -792,7 +795,7 @@ msgid "Cronjobs"
|
|
792 |
msgstr "Scheduled Tasks"
|
793 |
|
794 |
msgid "CronjobsInfo"
|
795 |
-
msgstr "
|
796 |
|
797 |
msgid "CronjobRunNow"
|
798 |
msgstr "Execute Now (in +10 seconds)"
|
@@ -1016,9 +1019,6 @@ msgstr "Newest WordPress"
|
|
1016 |
msgid "NoUpdates"
|
1017 |
msgstr "There are no updates available."
|
1018 |
|
1019 |
-
msgid "ScannerFreqStatus"
|
1020 |
-
msgstr "The file system scanner frequency has been changed"
|
1021 |
-
|
1022 |
msgid "SiteClean"
|
1023 |
msgstr "Site is Clean"
|
1024 |
|
@@ -1346,14 +1346,8 @@ msgstr "Your website has no <code>.htaccess</code> file or it was not found in t
|
|
1346 |
msgid "HTAccessStandard"
|
1347 |
msgstr "The main <code>.htaccess</code> file in your site has the standard rules for a WordPress installation. You can customize it to improve the performance and change the behaviour of the redirections for pages and posts in your site. To get more information visit the official documentation at <a target=\"_blank\" rel=\"noopener\" href=\"https://codex.wordpress.org/Using_Permalinks#Creating_and_editing_.28.htaccess.29\"> Codex WordPress - Creating and editing (.htaccess)</a>"
|
1348 |
|
1349 |
-
msgid "ScannerTitle"
|
1350 |
-
msgstr "Scanner Settings"
|
1351 |
-
|
1352 |
-
msgid "ScannerFrequency"
|
1353 |
-
msgstr "Scanning Frequency"
|
1354 |
-
|
1355 |
msgid "ScannerDescription"
|
1356 |
-
msgstr "The plugin scans your entire website looking for changes which are later reported via the API in the audit logs page. This scanner runs
|
1357 |
|
1358 |
msgid "ScannerWithoutSPL"
|
1359 |
msgstr "The scanner uses the <a href=\"http://php.net/manual/en/class.splfileobject.php\" target=\"_blank\" rel=\"noopener\">PHP SPL library</a> and the <a target=\"_blank\" href=\"http://php.net/manual/en/class.filesystemiterator.php\" rel=\"noopener\">Filesystem Iterator</a> class to scan the directory tree where your website is located in the server. This library is only available on PHP 5 >= 5.3.0 — OR — PHP 7; if you have an older version of PHP the plugin will not work as expected. Please ask your hosting provider to advice you on this matter."
|
@@ -1466,15 +1460,6 @@ msgstr "Data Storage"
|
|
1466 |
msgid "DataStorageInfo"
|
1467 |
msgstr "This is the directory where the plugin will store the security logs, the list of files marked as fixed in the core integrity tool, the cache for the malware scanner and 3rd-party plugin metadata. The plugin requires write permissions in this directory as well as the files contained in it. If you prefer to keep these files in a non-public directory <em>(one level up the document root) </em> please define a constant in the <em>\"wp-config.php\"</em> file named <em>\"SUCURI_DATA_STORAGE\"</em> with the absolute path to the new directory."
|
1468 |
|
1469 |
-
msgid "CommentMonitor"
|
1470 |
-
msgstr "Comment Monitor"
|
1471 |
-
|
1472 |
-
msgid "CommentMonitorStatus"
|
1473 |
-
msgstr "The status of the comment monitor has been changed"
|
1474 |
-
|
1475 |
-
msgid "CommentMonitorInfo"
|
1476 |
-
msgstr "User comments are the main source of spam in WordPress websites, this option enables the monitoring of data sent via the comment forms loaded in every page and post. We also use this information in an anonymous way to generate <a target=\"_blank\" href=\"https://sucuri.net/security-reports/brute-force/\">statistics</a> of usage that help us improve our service."
|
1477 |
-
|
1478 |
msgid "LogsReport"
|
1479 |
msgstr "Audit Log Statistics"
|
1480 |
|
194 |
msgid "Refresh"
|
195 |
msgstr "Refresh"
|
196 |
|
197 |
+
msgid "AuditLogsNoAPI"
|
198 |
+
msgstr "The API service is not available; logs are coming from the local server"
|
199 |
+
|
200 |
+
msgid "AuditLogsQueue"
|
201 |
+
msgstr "logs in the queue"
|
202 |
+
|
203 |
+
msgid "SendLogs"
|
204 |
+
msgstr "Send Logs"
|
205 |
+
|
206 |
msgid "UnsupportedWordPress"
|
207 |
msgstr "WordPress version is not supported."
|
208 |
|
773 |
msgid "APIServiceChanged"
|
774 |
msgstr "The status of the API service has been changed"
|
775 |
|
|
|
|
|
|
|
|
|
|
|
|
|
776 |
msgid "PluginResetSuccess"
|
777 |
msgstr "Local security logs, hardening and settings were deleted"
|
778 |
|
795 |
msgstr "Scheduled Tasks"
|
796 |
|
797 |
msgid "CronjobsInfo"
|
798 |
+
msgstr "Scheduled tasks are rules registered in your database by a plugin, theme, or the base system itself; they are used to automatically execute actions defined in the code every certain amount of time. A good use of these rules is to generate backup files of your site, execute a security scanner, or remove unused elements like drafts. <b>Note:</b> Scheduled tasks can be re-installed by any plugin/theme automatically, consider to deactivate the plugin entirely if you want to get rid of the scheduled tasks."
|
799 |
|
800 |
msgid "CronjobRunNow"
|
801 |
msgstr "Execute Now (in +10 seconds)"
|
1019 |
msgid "NoUpdates"
|
1020 |
msgstr "There are no updates available."
|
1021 |
|
|
|
|
|
|
|
1022 |
msgid "SiteClean"
|
1023 |
msgstr "Site is Clean"
|
1024 |
|
1346 |
msgid "HTAccessStandard"
|
1347 |
msgstr "The main <code>.htaccess</code> file in your site has the standard rules for a WordPress installation. You can customize it to improve the performance and change the behaviour of the redirections for pages and posts in your site. To get more information visit the official documentation at <a target=\"_blank\" rel=\"noopener\" href=\"https://codex.wordpress.org/Using_Permalinks#Creating_and_editing_.28.htaccess.29\"> Codex WordPress - Creating and editing (.htaccess)</a>"
|
1348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1349 |
msgid "ScannerDescription"
|
1350 |
+
msgstr "The plugin scans your entire website looking for changes which are later reported via the API in the audit logs page. This scanner runs daily but you can change the frequency to meet your own requirements. Notice that scanning your project files too frequently will affect the performance of your website. Be sure to have enough server resources before changing this option. The memory limit and maximum execution time are two of the PHP options that your server will set to stop your website from consuming too much resources."
|
1351 |
|
1352 |
msgid "ScannerWithoutSPL"
|
1353 |
msgstr "The scanner uses the <a href=\"http://php.net/manual/en/class.splfileobject.php\" target=\"_blank\" rel=\"noopener\">PHP SPL library</a> and the <a target=\"_blank\" href=\"http://php.net/manual/en/class.filesystemiterator.php\" rel=\"noopener\">Filesystem Iterator</a> class to scan the directory tree where your website is located in the server. This library is only available on PHP 5 >= 5.3.0 — OR — PHP 7; if you have an older version of PHP the plugin will not work as expected. Please ask your hosting provider to advice you on this matter."
|
1460 |
msgid "DataStorageInfo"
|
1461 |
msgstr "This is the directory where the plugin will store the security logs, the list of files marked as fixed in the core integrity tool, the cache for the malware scanner and 3rd-party plugin metadata. The plugin requires write permissions in this directory as well as the files contained in it. If you prefer to keep these files in a non-public directory <em>(one level up the document root) </em> please define a constant in the <em>\"wp-config.php\"</em> file named <em>\"SUCURI_DATA_STORAGE\"</em> with the absolute path to the new directory."
|
1462 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1463 |
msgid "LogsReport"
|
1464 |
msgstr "Audit Log Statistics"
|
1465 |
|
languages/sucuri-scanner-es_ES.mo
CHANGED
Binary file
|
languages/sucuri-scanner-es_ES.po
CHANGED
@@ -194,6 +194,15 @@ msgstr "Los registros son guardados por %%SUCURI.AuditLogs.Lifetime%% segundos"
|
|
194 |
msgid "Refresh"
|
195 |
msgstr "Actualizar"
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
msgid "UnsupportedWordPress"
|
198 |
msgstr "esta versión de WordPress no tiene soporte."
|
199 |
|
@@ -764,12 +773,6 @@ msgstr "Este tipo de publicaciones no es válido o ya han sido ignoradas"
|
|
764 |
msgid "APIServiceChanged"
|
765 |
msgstr "El estado de comunicación con la API ha sido cambiado"
|
766 |
|
767 |
-
msgid "HTTPTimeoutChange"
|
768 |
-
msgstr "El tiempo de espera para las conexiones a través de HTTP ha sido cambiado"
|
769 |
-
|
770 |
-
msgid "HTTPTimeoutFailure"
|
771 |
-
msgstr "El tiempo de espera para las conexiones a través de HTTP es muy alto"
|
772 |
-
|
773 |
msgid "PluginResetSuccess"
|
774 |
msgstr "Los registros de seguridad, configuraciones y cambios adicionales hechos por el plugin han sido eliminados"
|
775 |
|
@@ -792,7 +795,7 @@ msgid "Cronjobs"
|
|
792 |
msgstr "Acciones Automatizadas"
|
793 |
|
794 |
msgid "CronjobsInfo"
|
795 |
-
msgstr "
|
796 |
|
797 |
msgid "CronjobRunNow"
|
798 |
msgstr "Ejecutar Ahora (en +10 segundos)"
|
@@ -1016,9 +1019,6 @@ msgstr "Última Versión"
|
|
1016 |
msgid "NoUpdates"
|
1017 |
msgstr "No existen actualizaciones."
|
1018 |
|
1019 |
-
msgid "ScannerFreqStatus"
|
1020 |
-
msgstr "La frecuencia para la ejecución del escáner de archivos ha sido cambiada"
|
1021 |
-
|
1022 |
msgid "SiteClean"
|
1023 |
msgstr "Sitio Limpio"
|
1024 |
|
@@ -1346,14 +1346,8 @@ msgstr "El sitio web no tiene un archivo <code>.htaccess</code> o no se encuentr
|
|
1346 |
msgid "HTAccessStandard"
|
1347 |
msgstr "El archivo <code>.htaccess</code> principal contiene las reglas estándares de WordPress generadas durante la instalación del sitio web. Usted puede modificar estas reglas para aumentar el rendimiento del servidor o para generar redirecciones a otras páginas. Para obtener más información al respecto visite la página oficial con la documentación en <a target=\"_blank\" rel=\"noopener\" href=\"https://codex.wordpress.org/Using_Permalinks#Creating_and_editing_.28.htaccess.29\"> Codex WordPress - Creating and editing (.htaccess)</a>"
|
1348 |
|
1349 |
-
msgid "ScannerTitle"
|
1350 |
-
msgstr "Ajustes para el Escáner"
|
1351 |
-
|
1352 |
-
msgid "ScannerFrequency"
|
1353 |
-
msgstr "Frecuencia de Ejecución"
|
1354 |
-
|
1355 |
msgid "ScannerDescription"
|
1356 |
-
msgstr "El plugin escanea su sitio web en busca de cambios que son eventualmente reportados a la API y visualizados a través de los registros de seguridad. Este escáner es ejecutado automáticamente cada
|
1357 |
|
1358 |
msgid "ScannerWithoutSPL"
|
1359 |
msgstr "El escáner hace uso de las librerías <a href=\"http://php.net/manual/en/class.splfileobject.php\" target=\"_blank\" rel=\"noopener\">SPL</a> y <a target=\"_blank\" href=\"http://php.net/manual/en/class.filesystemiterator.php\" rel=\"noopener\">Filesystem Iterator</a> de PHP para escanear el árbol de directorios de su sitio web. Esta librería solo está disponible en PHP 5 >= 5.3.0 — y — PHP 7; si su servidor hace uso de una versión antigua el plugin no funcionará como se espera. Por favor, contacte a su proveedor de hosting para obtener ayuda al respecto."
|
@@ -1466,15 +1460,6 @@ msgstr "Almacenamiento de Datos"
|
|
1466 |
msgid "DataStorageInfo"
|
1467 |
msgstr "Este es el directorio donde el plugin guardará los registros de seguridad, el archivo con las configuraciones, la cache y datos adicionales de otras herramientas. El plugin require de permisos de escritura en este directorio así como en los archivos contenidos allí. Si usted prefiere mantener estos archivos en un directorio diferente al especificado, por favor defina una constante llamada <em>\"SUCURI_DATA_STORAGE\"</em> en el archivo de configuración de WordPress con la ruta absoluta del nuevo directorio."
|
1468 |
|
1469 |
-
msgid "CommentMonitor"
|
1470 |
-
msgstr "Monitor de Comentarios"
|
1471 |
-
|
1472 |
-
msgid "CommentMonitorStatus"
|
1473 |
-
msgstr "El estado del monitor de comentarios ha sido cambiado"
|
1474 |
-
|
1475 |
-
msgid "CommentMonitorInfo"
|
1476 |
-
msgstr "Los comentarios de usuario son el origen principal de spam en sitios que usan WordPress, esta opción activa el monitoreo de los datos enviados a través de formularios de comentario disponibles en cada página. Nosotros también usamos esta información de forma anónima para generar <a target=\"_blank\" href=\"https://sucuri.net/security-reports/brute-force/\">estadísticas</a> de uso para ayudarnos a mejorar el servicio."
|
1477 |
-
|
1478 |
msgid "LogsReport"
|
1479 |
msgstr "Estadísticas De Seguridad"
|
1480 |
|
194 |
msgid "Refresh"
|
195 |
msgstr "Actualizar"
|
196 |
|
197 |
+
msgid "AuditLogsNoAPI"
|
198 |
+
msgstr "La API no está disponible; la información viene del servidor local"
|
199 |
+
|
200 |
+
msgid "AuditLogsQueue"
|
201 |
+
msgstr "registros en cola"
|
202 |
+
|
203 |
+
msgid "SendLogs"
|
204 |
+
msgstr "Enviar"
|
205 |
+
|
206 |
msgid "UnsupportedWordPress"
|
207 |
msgstr "esta versión de WordPress no tiene soporte."
|
208 |
|
773 |
msgid "APIServiceChanged"
|
774 |
msgstr "El estado de comunicación con la API ha sido cambiado"
|
775 |
|
|
|
|
|
|
|
|
|
|
|
|
|
776 |
msgid "PluginResetSuccess"
|
777 |
msgstr "Los registros de seguridad, configuraciones y cambios adicionales hechos por el plugin han sido eliminados"
|
778 |
|
795 |
msgstr "Acciones Automatizadas"
|
796 |
|
797 |
msgid "CronjobsInfo"
|
798 |
+
msgstr "Acciones automatizadas son reglas registradas en su base de datos por un plugin, plantilla o WordPress; estas reglas son usadas para ejecutar automáticamente acciones definidas en el código con un intervalo de tiempo definido. Un buen uso de estas reglas es la generación de copias de seguridad, la ejecución de escáneres de seguridad o la remoción de elementos innecesarios de la base de datos como borradores de publicaciones. <b>Nota:</b> Las acciones automatizadas pueden ser re-instaladas por cualquier plugin/plantilla automáticamente, considere desactivar el plugin completamente si quiere eliminar una de estas acciones."
|
799 |
|
800 |
msgid "CronjobRunNow"
|
801 |
msgstr "Ejecutar Ahora (en +10 segundos)"
|
1019 |
msgid "NoUpdates"
|
1020 |
msgstr "No existen actualizaciones."
|
1021 |
|
|
|
|
|
|
|
1022 |
msgid "SiteClean"
|
1023 |
msgstr "Sitio Limpio"
|
1024 |
|
1346 |
msgid "HTAccessStandard"
|
1347 |
msgstr "El archivo <code>.htaccess</code> principal contiene las reglas estándares de WordPress generadas durante la instalación del sitio web. Usted puede modificar estas reglas para aumentar el rendimiento del servidor o para generar redirecciones a otras páginas. Para obtener más información al respecto visite la página oficial con la documentación en <a target=\"_blank\" rel=\"noopener\" href=\"https://codex.wordpress.org/Using_Permalinks#Creating_and_editing_.28.htaccess.29\"> Codex WordPress - Creating and editing (.htaccess)</a>"
|
1348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1349 |
msgid "ScannerDescription"
|
1350 |
+
msgstr "El plugin escanea su sitio web en busca de cambios que son eventualmente reportados a la API y visualizados a través de los registros de seguridad. Este escáner es ejecutado automáticamente cada día pero usted puede cambiar la frecuencia dependiendo de sus necesidades. Tenga en cuenta que si su sitio contiene una gran cantidad de archivos es posible que el escáner sea bloqueado por su proveedor de hosting si este excede el límite de ejecución que ellos hayan impuesto sobre su cuenta."
|
1351 |
|
1352 |
msgid "ScannerWithoutSPL"
|
1353 |
msgstr "El escáner hace uso de las librerías <a href=\"http://php.net/manual/en/class.splfileobject.php\" target=\"_blank\" rel=\"noopener\">SPL</a> y <a target=\"_blank\" href=\"http://php.net/manual/en/class.filesystemiterator.php\" rel=\"noopener\">Filesystem Iterator</a> de PHP para escanear el árbol de directorios de su sitio web. Esta librería solo está disponible en PHP 5 >= 5.3.0 — y — PHP 7; si su servidor hace uso de una versión antigua el plugin no funcionará como se espera. Por favor, contacte a su proveedor de hosting para obtener ayuda al respecto."
|
1460 |
msgid "DataStorageInfo"
|
1461 |
msgstr "Este es el directorio donde el plugin guardará los registros de seguridad, el archivo con las configuraciones, la cache y datos adicionales de otras herramientas. El plugin require de permisos de escritura en este directorio así como en los archivos contenidos allí. Si usted prefiere mantener estos archivos en un directorio diferente al especificado, por favor defina una constante llamada <em>\"SUCURI_DATA_STORAGE\"</em> en el archivo de configuración de WordPress con la ruta absoluta del nuevo directorio."
|
1462 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1463 |
msgid "LogsReport"
|
1464 |
msgstr "Estadísticas De Seguridad"
|
1465 |
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: dd@sucuri.net
|
|
3 |
Donate Link: https://sucuri.net/
|
4 |
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection, WordPress Security, Login Security, Security Auditing, File Integrity, htaccess, phishing, backdoors, SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Security, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
|
5 |
Requires at least: 3.6
|
6 |
-
Stable tag: 1.8.
|
7 |
Tested up to: 4.8.0
|
8 |
|
9 |
The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
|
@@ -216,11 +216,23 @@ No, it is not required. The Website Firewall runs in the cloud without the need
|
|
216 |
|
217 |
== Upgrade Notice ==
|
218 |
|
219 |
-
= 1.8.
|
220 |
This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.
|
221 |
|
222 |
== Changelog ==
|
223 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
224 |
= 1.8.6 =
|
225 |
* Add default language for internationalization fallback
|
226 |
|
3 |
Donate Link: https://sucuri.net/
|
4 |
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection, WordPress Security, Login Security, Security Auditing, File Integrity, htaccess, phishing, backdoors, SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Security, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
|
5 |
Requires at least: 3.6
|
6 |
+
Stable tag: 1.8.7
|
7 |
Tested up to: 4.8.0
|
8 |
|
9 |
The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
|
216 |
|
217 |
== Upgrade Notice ==
|
218 |
|
219 |
+
= 1.8.7 =
|
220 |
This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.
|
221 |
|
222 |
== Changelog ==
|
223 |
|
224 |
+
= 1.8.7 =
|
225 |
+
* Fix multiple issues with the API calls
|
226 |
+
* Add queue system to fix website performance
|
227 |
+
* Fix non-dismissable newsletter invitation message
|
228 |
+
* Fix performance of the audit log parser without regexp
|
229 |
+
* Add conditional to check for the availability of SPL
|
230 |
+
* Add cache for the audit logs to make dashboard responsive
|
231 |
+
* Modify frequency of the file system scans to run daily
|
232 |
+
* Remove option to configure the maximum API timeout
|
233 |
+
* Modify location of the scanner options and scheduled tasks
|
234 |
+
* Add button to send the logs from the queue to the API
|
235 |
+
|
236 |
= 1.8.6 =
|
237 |
* Add default language for internationalization fallback
|
238 |
|
src/api.lib.php
CHANGED
@@ -37,31 +37,6 @@ if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) {
|
|
37 |
*/
|
38 |
class SucuriScanAPI extends SucuriScanOption
|
39 |
{
|
40 |
-
/**
|
41 |
-
* Seconds before consider a HTTP request as timeout.
|
42 |
-
*
|
43 |
-
* As for the 01/Jan/2016 if the number of seconds before a timeout is greater
|
44 |
-
* than sixty (which is one minute) the method will reset the option to its
|
45 |
-
* default value to keep the latency of the HTTP requests in a minimum to
|
46 |
-
* minimize the interruptions in the admins workflow. The normal connection
|
47 |
-
* timeout should be in the range of ten seconds, or fifteen if the DNS lookups
|
48 |
-
* are slow.
|
49 |
-
*
|
50 |
-
* @return int Seconds to consider a HTTP request timeout.
|
51 |
-
*/
|
52 |
-
public static function requestTimeout()
|
53 |
-
{
|
54 |
-
$timeout = (int) self::getOption(':request_timeout');
|
55 |
-
|
56 |
-
if ($timeout > SUCURISCAN_MAX_REQUEST_TIMEOUT) {
|
57 |
-
self::deleteOption(':request_timeout');
|
58 |
-
|
59 |
-
return self::requestTimeout();
|
60 |
-
}
|
61 |
-
|
62 |
-
return $timeout;
|
63 |
-
}
|
64 |
-
|
65 |
/**
|
66 |
* Alternative to the built-in PHP method http_build_query.
|
67 |
*
|
@@ -108,7 +83,7 @@ class SucuriScanAPI extends SucuriScanOption
|
|
108 |
}
|
109 |
|
110 |
$response = null;
|
111 |
-
$timeout =
|
112 |
$args = is_array($args) ? $args : array();
|
113 |
|
114 |
if (isset($args['timeout'])) {
|
@@ -259,10 +234,9 @@ class SucuriScanAPI extends SucuriScanOption
|
|
259 |
* for the first time.
|
260 |
*
|
261 |
* @param array $response HTTP response after API endpoint execution.
|
262 |
-
* @param bool $enqueue Add the log to the local queue on a failure.
|
263 |
* @return bool False if the API call failed, true otherwise.
|
264 |
*/
|
265 |
-
public static function handleResponse($response = array()
|
266 |
{
|
267 |
if (!$response || getenv('SUCURISCAN_NO_API_HANDLE')) {
|
268 |
return false;
|
@@ -324,7 +298,7 @@ class SucuriScanAPI extends SucuriScanOption
|
|
324 |
$msg = __('ErrorInvalidEmail', SUCURISCAN_TEXTDOMAIN);
|
325 |
}
|
326 |
|
327 |
-
return SucuriScanInterface::error($
|
328 |
}
|
329 |
|
330 |
/**
|
@@ -348,7 +322,7 @@ class SucuriScanAPI extends SucuriScanOption
|
|
348 |
if (self::handleResponse($response)) {
|
349 |
self::setPluginKey($response['output']['api_key']);
|
350 |
|
351 |
-
SucuriScanEvent::
|
352 |
SucuriScanEvent::notifyEvent('plugin_change', 'API key was generated and set');
|
353 |
return SucuriScanInterface::info(__('AlertAPIKeySet', SUCURISCAN_TEXTDOMAIN));
|
354 |
}
|
@@ -379,58 +353,6 @@ class SucuriScanAPI extends SucuriScanOption
|
|
379 |
return false;
|
380 |
}
|
381 |
|
382 |
-
/**
|
383 |
-
* Send a request to the API to store and analyze the events of the site. An
|
384 |
-
* event can be anything from a simple request, an internal modification of the
|
385 |
-
* settings or files in the administrator panel, or a notification generated by
|
386 |
-
* this plugin.
|
387 |
-
*
|
388 |
-
* @param string $event Event triggered by the core system functions.
|
389 |
-
* @param int $time Timestamp when the event was originally triggered.
|
390 |
-
* @param bool $enqueue Add the log to the local queue on a failure.
|
391 |
-
* @return bool True if the event was logged, false otherwise.
|
392 |
-
*/
|
393 |
-
public static function sendLog($event = '', $time = 0, $enqueue = true)
|
394 |
-
{
|
395 |
-
if (empty($event)) {
|
396 |
-
return self::throwException('Event identifier cannot be empty');
|
397 |
-
}
|
398 |
-
|
399 |
-
$params = array();
|
400 |
-
$params['a'] = 'send_log';
|
401 |
-
$params['m'] = $event;
|
402 |
-
|
403 |
-
if (intval($time) > 0) {
|
404 |
-
$params['time'] = (int) $time;
|
405 |
-
}
|
406 |
-
|
407 |
-
$response = self::apiCallWordpress('POST', $params, true);
|
408 |
-
|
409 |
-
return self::handleResponse($response, $enqueue);
|
410 |
-
}
|
411 |
-
|
412 |
-
/**
|
413 |
-
* Send all logs from the queue.
|
414 |
-
*
|
415 |
-
* Retry the HTTP calls for the logs that were not sent to the API service
|
416 |
-
* because of a connection failure or misconfiguration. Each successful call
|
417 |
-
* will remove the log from the queue and the failures will keep them until the
|
418 |
-
* next method call is executed.
|
419 |
-
*/
|
420 |
-
public static function sendLogsFromQueue()
|
421 |
-
{
|
422 |
-
$cache = new SucuriScanCache('auditqueue');
|
423 |
-
$entries = $cache->getAll();
|
424 |
-
|
425 |
-
if (is_array($entries) && !empty($entries)) {
|
426 |
-
foreach ($entries as $key => $entry) {
|
427 |
-
if (self::sendLog($entry->message, $entry->created_at, false)) {
|
428 |
-
$cache->delete($key);
|
429 |
-
}
|
430 |
-
}
|
431 |
-
}
|
432 |
-
}
|
433 |
-
|
434 |
/**
|
435 |
* Retrieve the event logs registered by the API service.
|
436 |
*
|
@@ -452,36 +374,27 @@ class SucuriScanAPI extends SucuriScanOption
|
|
452 |
}
|
453 |
|
454 |
/**
|
455 |
-
*
|
456 |
*
|
457 |
-
* @
|
458 |
-
* @return array|bool The data structure with the logs.
|
459 |
*/
|
460 |
-
public static function
|
461 |
{
|
462 |
-
if (SucuriScanOption::isDisabled(':selfhosting_monitor')) {
|
463 |
-
return self::throwException('Self-hosting monitor is disabled');
|
464 |
-
}
|
465 |
-
|
466 |
$auditlogs = array();
|
467 |
-
$
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
$
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
if (!empty($line)) {
|
482 |
-
$auditlogs[] = $line;
|
483 |
-
}
|
484 |
-
$file->next();
|
485 |
}
|
486 |
}
|
487 |
|
@@ -505,94 +418,116 @@ class SucuriScanAPI extends SucuriScanOption
|
|
505 |
{
|
506 |
$response = is_array($response) ? $response : array();
|
507 |
$response['output_data'] = array();
|
508 |
-
$log_pattern = '/^([0-9\-]+) ([0-9:]+) (\S+) : (.+)/';
|
509 |
-
$extra_pattern = '/(.+ \(multiple entries\):) (.+)/';
|
510 |
-
$generic_pattern = '/^@?([A-Z][a-z]{3,7}): ([^;]+; )?(.+)/';
|
511 |
-
$auth_pattern = '/^User authentication (succeeded|failed): ([^<;]+)/';
|
512 |
|
513 |
foreach ((array) @$response['output'] as $log) {
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
'time' => '',
|
519 |
-
'datetime' => '',
|
520 |
-
'timestamp' => 0,
|
521 |
-
'account' => $log_match[3],
|
522 |
-
'username' => 'system',
|
523 |
-
'remote_addr' => '127.0.0.1',
|
524 |
-
'message' => $log_match[4],
|
525 |
-
'file_list' => false,
|
526 |
-
'file_list_count' => 0,
|
527 |
-
);
|
528 |
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
/* extract the username and remote address from the log */
|
544 |
-
if (!empty($log_extra[2])) {
|
545 |
-
$username_address = rtrim($log_extra[2], ";\x20");
|
546 |
-
$log_data['remote_addr'] = $username_address;
|
547 |
-
|
548 |
-
/* separate the username from the remote address */
|
549 |
-
if (strpos($username_address, ",\x20") !== false) {
|
550 |
-
$usip_parts = explode(",\x20", $username_address, 2);
|
551 |
-
|
552 |
-
if (count($usip_parts) == 2) {
|
553 |
-
/* separate the username from the display name */
|
554 |
-
$log_data['username'] = @preg_replace('/^.+ \((.+)\)$/', '$1', $usip_parts[0]);
|
555 |
-
$log_data['remote_addr'] = $usip_parts[1];
|
556 |
-
}
|
557 |
-
}
|
558 |
-
}
|
559 |
|
560 |
-
|
561 |
-
|
562 |
-
'logged in',
|
563 |
-
'authentication succeeded',
|
564 |
-
$log_data['message']
|
565 |
-
);
|
566 |
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
571 |
|
572 |
-
/*
|
573 |
-
if (
|
574 |
-
|
575 |
-
$log_extra[2] = str_replace(', new size', '; new size', $log_extra[2]);
|
576 |
-
$log_extra[2] = str_replace(",\x20", ";\x20", $log_extra[2]);
|
577 |
-
$log_data['file_list'] = explode(',', $log_extra[2]);
|
578 |
-
$log_data['file_list_count'] = count($log_data['file_list']);
|
579 |
}
|
580 |
|
581 |
-
/* extract
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
$details = substr($log_data['message'], $idx + 11);
|
586 |
|
587 |
-
|
588 |
-
|
589 |
-
$
|
|
|
|
|
590 |
}
|
591 |
|
592 |
-
|
593 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
594 |
}
|
595 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
596 |
}
|
597 |
|
598 |
return $response;
|
@@ -617,14 +552,18 @@ class SucuriScanAPI extends SucuriScanOption
|
|
617 |
*
|
618 |
* @see https://wordpress.org/plugins/php-compatibility-checker/
|
619 |
*/
|
620 |
-
if (isset($data['message'])
|
621 |
-
|
622 |
-
|
623 |
-
|
|
|
|
|
|
|
|
|
624 |
$data['message'] = sprintf(
|
625 |
'WP Engine PHP Compatibility Checker: %s (created post #%d as cache)',
|
626 |
-
$
|
627 |
-
$
|
628 |
);
|
629 |
}
|
630 |
|
@@ -725,16 +664,22 @@ class SucuriScanAPI extends SucuriScanOption
|
|
725 |
$report['end_timestamp'] = $event['timestamp'];
|
726 |
}
|
727 |
|
728 |
-
|
729 |
-
if (
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
// Backward compatibility for previous user login messages.
|
737 |
$report['events_per_login']['successful']++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
738 |
}
|
739 |
}
|
740 |
|
@@ -854,11 +799,18 @@ class SucuriScanAPI extends SucuriScanOption
|
|
854 |
* distributed by an independent developer.
|
855 |
*/
|
856 |
if (isset($plugin_data['PluginURI'])
|
857 |
-
&&
|
|
|
858 |
) {
|
859 |
-
$repository = $match[0];
|
860 |
-
$repository_name = $match[2];
|
861 |
$is_free_plugin = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
862 |
} else {
|
863 |
$delimiter = strpos($path, '/') ? '/' : '.';
|
864 |
$parts = explode($delimiter, $path, 2);
|
37 |
*/
|
38 |
class SucuriScanAPI extends SucuriScanOption
|
39 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
/**
|
41 |
* Alternative to the built-in PHP method http_build_query.
|
42 |
*
|
83 |
}
|
84 |
|
85 |
$response = null;
|
86 |
+
$timeout = SUCURISCAN_MAX_REQUEST_TIMEOUT;
|
87 |
$args = is_array($args) ? $args : array();
|
88 |
|
89 |
if (isset($args['timeout'])) {
|
234 |
* for the first time.
|
235 |
*
|
236 |
* @param array $response HTTP response after API endpoint execution.
|
|
|
237 |
* @return bool False if the API call failed, true otherwise.
|
238 |
*/
|
239 |
+
public static function handleResponse($response = array())
|
240 |
{
|
241 |
if (!$response || getenv('SUCURISCAN_NO_API_HANDLE')) {
|
242 |
return false;
|
298 |
$msg = __('ErrorInvalidEmail', SUCURISCAN_TEXTDOMAIN);
|
299 |
}
|
300 |
|
301 |
+
return SucuriScanInterface::error($msg);
|
302 |
}
|
303 |
|
304 |
/**
|
322 |
if (self::handleResponse($response)) {
|
323 |
self::setPluginKey($response['output']['api_key']);
|
324 |
|
325 |
+
SucuriScanEvent::installScheduledTask();
|
326 |
SucuriScanEvent::notifyEvent('plugin_change', 'API key was generated and set');
|
327 |
return SucuriScanInterface::info(__('AlertAPIKeySet', SUCURISCAN_TEXTDOMAIN));
|
328 |
}
|
353 |
return false;
|
354 |
}
|
355 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
356 |
/**
|
357 |
* Retrieve the event logs registered by the API service.
|
358 |
*
|
374 |
}
|
375 |
|
376 |
/**
|
377 |
+
* Returns the security logs from the system queue.
|
378 |
*
|
379 |
+
* @return array The data structure with the logs.
|
|
|
380 |
*/
|
381 |
+
public static function getAuditLogsFromQueue()
|
382 |
{
|
|
|
|
|
|
|
|
|
383 |
$auditlogs = array();
|
384 |
+
$cache = new SucuriScanCache('auditqueue');
|
385 |
+
|
386 |
+
if ($events = $cache->getAll()) {
|
387 |
+
$events = array_reverse($events);
|
388 |
+
|
389 |
+
foreach ($events as $micro => $message) {
|
390 |
+
$offset = strpos($micro, '_');
|
391 |
+
$time = substr($micro, 0, $offset);
|
392 |
+
$auditlogs[] = sprintf(
|
393 |
+
'%s %s : %s',
|
394 |
+
date('Y-m-d H:i:s', intval($time)),
|
395 |
+
SucuriScan::getSiteEmail(),
|
396 |
+
$message
|
397 |
+
);
|
|
|
|
|
|
|
|
|
398 |
}
|
399 |
}
|
400 |
|
418 |
{
|
419 |
$response = is_array($response) ? $response : array();
|
420 |
$response['output_data'] = array();
|
|
|
|
|
|
|
|
|
421 |
|
422 |
foreach ((array) @$response['output'] as $log) {
|
423 |
+
/* YYYY-MM-dd HH:ii:ss EMAIL : MESSAGE: (multiple entries): a,b,c */
|
424 |
+
if (strpos($log, "\x20:\x20") === false) {
|
425 |
+
continue; /* ignore; invalid format */
|
426 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
427 |
|
428 |
+
$log_data = array(
|
429 |
+
'event' => 'notice',
|
430 |
+
'date' => '',
|
431 |
+
'time' => '',
|
432 |
+
'datetime' => '',
|
433 |
+
'timestamp' => 0,
|
434 |
+
'account' => '',
|
435 |
+
'username' => 'system',
|
436 |
+
'remote_addr' => '127.0.0.1',
|
437 |
+
'message' => '',
|
438 |
+
'file_list' => false,
|
439 |
+
'file_list_count' => 0,
|
440 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
441 |
|
442 |
+
list($left, $right) = explode("\x20:\x20", $log, 2);
|
443 |
+
$dateAndEmail = explode("\x20", $left, 3);
|
|
|
|
|
|
|
|
|
444 |
|
445 |
+
/* set basic information */
|
446 |
+
$log_data['message'] = $right;
|
447 |
+
$log_data['account'] = $dateAndEmail[2];
|
448 |
+
|
449 |
+
/* extract and fix the date and time using the Eastern time zone */
|
450 |
+
$datetime = sprintf('%s %s EDT', $dateAndEmail[0], $dateAndEmail[1]);
|
451 |
+
$log_data['timestamp'] = strtotime($datetime);
|
452 |
+
$log_data['datetime'] = date('Y-m-d H:i:s', $log_data['timestamp']);
|
453 |
+
$log_data['date'] = date('Y-m-d', $log_data['timestamp']);
|
454 |
+
$log_data['time'] = date('H:i:s', $log_data['timestamp']);
|
455 |
+
|
456 |
+
/* extract more information from the generic audit logs */
|
457 |
+
$log_data['message'] = str_replace('<br>', ";\x20", $log_data['message']);
|
458 |
+
|
459 |
+
$eventTypes = self::getAuditEventTypes();
|
460 |
+
$eventTypes = array_keys($eventTypes);
|
461 |
+
|
462 |
+
/* LEVEL: USERNAME, IP; MESSAGE */
|
463 |
+
if (strpos($log_data['message'], ":\x20") && strpos($log_data['message'], ";\x20")) {
|
464 |
+
$offset = strpos($log_data['message'], ":\x20");
|
465 |
+
$level = substr($log_data['message'], 0, $offset);
|
466 |
+
$log_data['event'] = strtolower($level);
|
467 |
|
468 |
+
/* ignore; invalid event type */
|
469 |
+
if (!in_array($log_data['event'], $eventTypes)) {
|
470 |
+
continue;
|
|
|
|
|
|
|
|
|
471 |
}
|
472 |
|
473 |
+
/* extract the IP address */
|
474 |
+
$log_data['message'] = substr($log_data['message'], $offset+2);
|
475 |
+
$offset = strpos($log_data['message'], ";\x20");
|
476 |
+
$log_data['remote_addr'] = substr($log_data['message'], 0, $offset);
|
|
|
477 |
|
478 |
+
/* extract the username */
|
479 |
+
if (strpos($log_data['remote_addr'], ",\x20")) {
|
480 |
+
$index = strpos($log_data['remote_addr'], ",\x20");
|
481 |
+
$log_data['username'] = substr($log_data['remote_addr'], 0, $index);
|
482 |
+
$log_data['remote_addr'] = substr($log_data['remote_addr'], $index+2);
|
483 |
}
|
484 |
|
485 |
+
/* fix old user authentication logs for backward compatibility */
|
486 |
+
$log_data['message'] = substr($log_data['message'], $offset+2);
|
487 |
+
$log_data['message'] = str_replace(
|
488 |
+
'logged in',
|
489 |
+
'authentication succeeded',
|
490 |
+
$log_data['message']
|
491 |
+
);
|
492 |
+
|
493 |
+
/* extract the username of a successful/failed login */
|
494 |
+
if (strpos($log_data['message'], "User authentication\x20") === 0) {
|
495 |
+
$offset = strpos($log_data['message'], ":\x20");
|
496 |
+
$username = substr($log_data['message'], $offset+2);
|
497 |
+
if (strpos($username, ';') !== false) {
|
498 |
+
$username = substr($username, 0, strpos($username, ';'));
|
499 |
+
}
|
500 |
+
$log_data['username'] = $username;
|
501 |
}
|
502 |
}
|
503 |
+
|
504 |
+
/* extract more information from the special formatted logs */
|
505 |
+
if (strpos($log_data['message'], "(multiple entries):\x20")) {
|
506 |
+
$offset = strpos($log_data['message'], "(multiple entries):\x20");
|
507 |
+
$message = substr($log_data['message'], 0, $offset+19);
|
508 |
+
$entries = substr($log_data['message'], $offset+20);
|
509 |
+
|
510 |
+
$log_data['message'] = $message;
|
511 |
+
$entries = str_replace(', new size', '; new size', $entries);
|
512 |
+
$entries = str_replace(",\x20", ";\x20", $entries);
|
513 |
+
$log_data['file_list'] = explode(',', $entries);
|
514 |
+
$log_data['file_list_count'] = count($log_data['file_list']);
|
515 |
+
}
|
516 |
+
|
517 |
+
/* extract additional details from the message */
|
518 |
+
if (strpos($log_data['message'], '; details:')) {
|
519 |
+
$idx = strpos($log_data['message'], '; details:');
|
520 |
+
$message = substr($log_data['message'], 0, $idx);
|
521 |
+
$details = substr($log_data['message'], $idx + 11);
|
522 |
+
|
523 |
+
$log_data['message'] = $message . ' (details):';
|
524 |
+
$log_data['file_list'] = explode(',', $details);
|
525 |
+
$log_data['file_list_count'] = count($log_data['file_list']);
|
526 |
+
}
|
527 |
+
|
528 |
+
if ($log_data = self::getLogsHotfix($log_data)) {
|
529 |
+
$response['output_data'][] = $log_data;
|
530 |
+
}
|
531 |
}
|
532 |
|
533 |
return $response;
|
552 |
*
|
553 |
* @see https://wordpress.org/plugins/php-compatibility-checker/
|
554 |
*/
|
555 |
+
if (isset($data['message']) && strpos($data['message'], 'Wpephpcompat_jobs') === 0) {
|
556 |
+
$offset = strpos($data['message'], "ID:\x20");
|
557 |
+
$id = substr($data['message'], $offset+4);
|
558 |
+
$id = substr($id, 0, strpos($id, ';'));
|
559 |
+
|
560 |
+
$offset = strpos($data['message'], "name:\x20");
|
561 |
+
$name = substr($data['message'], $offset+6);
|
562 |
+
|
563 |
$data['message'] = sprintf(
|
564 |
'WP Engine PHP Compatibility Checker: %s (created post #%d as cache)',
|
565 |
+
$name, /* plugin or theme name */
|
566 |
+
$id /* unique post or page identifier */
|
567 |
);
|
568 |
}
|
569 |
|
664 |
$report['end_timestamp'] = $event['timestamp'];
|
665 |
}
|
666 |
|
667 |
+
/* backward compatibility for previous user login messages */
|
668 |
+
if (strpos($event['message'], 'User logged in:') === 0) {
|
669 |
+
$report['events_per_login']['successful']++;
|
670 |
+
continue;
|
671 |
+
}
|
672 |
+
|
673 |
+
/* detect successful user authentications */
|
674 |
+
if (strpos($event['message'], 'User authentication succeeded:') === 0) {
|
|
|
675 |
$report['events_per_login']['successful']++;
|
676 |
+
continue;
|
677 |
+
}
|
678 |
+
|
679 |
+
/* detect failed user authentications */
|
680 |
+
if (strpos($event['message'], 'User authentication failed:') === 0) {
|
681 |
+
$report['events_per_login']['failed']++;
|
682 |
+
continue;
|
683 |
}
|
684 |
}
|
685 |
|
799 |
* distributed by an independent developer.
|
800 |
*/
|
801 |
if (isset($plugin_data['PluginURI'])
|
802 |
+
&& strpos($plugin_data['PluginURI'], '.org/plugins/')
|
803 |
+
&& strpos($plugin_data['PluginURI'], '://wordpress.org/')
|
804 |
) {
|
|
|
|
|
805 |
$is_free_plugin = true;
|
806 |
+
$repository = $plugin_data['PluginURI'];
|
807 |
+
$offset = strpos($plugin_data['PluginURI'], '/plugins/');
|
808 |
+
$repository_name = substr($plugin_data['PluginURI'], $offset+9);
|
809 |
+
|
810 |
+
if (strpos($repository_name, '/') !== false) {
|
811 |
+
$offset = strpos($repository_name, '/');
|
812 |
+
$repository_name = substr($repository_name, 0, $offset);
|
813 |
+
}
|
814 |
} else {
|
815 |
$delimiter = strpos($path, '/') ? '/' : '.';
|
816 |
$parts = explode($delimiter, $path, 2);
|
src/auditlogs.lib.php
CHANGED
@@ -64,10 +64,13 @@ class SucuriScanAuditLogs
|
|
64 |
|
65 |
$response = array();
|
66 |
$response['count'] = 0;
|
|
|
67 |
$response['content'] = '';
|
|
|
|
|
68 |
$response['selfhosting'] = false;
|
69 |
|
70 |
-
/*
|
71 |
$maxPerPage = SUCURISCAN_AUDITLOGS_PER_PAGE;
|
72 |
$pageNumber = SucuriScanTemplate::pageNumber();
|
73 |
$logsLimit = ($pageNumber * $maxPerPage);
|
@@ -81,17 +84,22 @@ class SucuriScanAuditLogs
|
|
81 |
/* API call if cache is invalid. */
|
82 |
if (!$auditlogs || $pageNumber !== 1) {
|
83 |
ob_start();
|
|
|
84 |
$cacheTheResponse = true;
|
85 |
$auditlogs = SucuriScanAPI::getAuditLogs($logsLimit);
|
86 |
-
$errors = ob_get_contents();
|
|
|
87 |
ob_end_clean();
|
|
|
|
|
|
|
|
|
|
|
88 |
}
|
89 |
|
90 |
-
/*
|
91 |
if (!empty($errors)) {
|
92 |
-
|
93 |
-
print($errors);
|
94 |
-
exit(0);
|
95 |
}
|
96 |
|
97 |
/* Cache the data for sometime. */
|
@@ -99,10 +107,21 @@ class SucuriScanAuditLogs
|
|
99 |
$cache->add('response', $auditlogs);
|
100 |
}
|
101 |
|
102 |
-
/*
|
103 |
-
if (
|
104 |
-
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
}
|
107 |
|
108 |
if ($auditlogs) {
|
@@ -197,6 +216,11 @@ class SucuriScanAuditLogs
|
|
197 |
$response['content'] = __('NoLogs', SUCURISCAN_TEXTDOMAIN);
|
198 |
}
|
199 |
|
|
|
|
|
|
|
|
|
|
|
200 |
wp_send_json($response, 200);
|
201 |
}
|
202 |
|
@@ -290,7 +314,7 @@ class SucuriScanAuditLogs
|
|
290 |
}
|
291 |
|
292 |
/**
|
293 |
-
*
|
294 |
*
|
295 |
* @codeCoverageIgnore - Notice that there is a test case that covers this
|
296 |
* code, but since the WP-Send-JSON method uses die() to stop any further
|
@@ -298,27 +322,15 @@ class SucuriScanAuditLogs
|
|
298 |
* with a missing line in the coverage. Since the test case takes care of
|
299 |
* the functionality of this code we will assume that it is fully covered.
|
300 |
*/
|
301 |
-
public static function
|
302 |
{
|
303 |
-
if (SucuriScanRequest::post('form_action') !== '
|
304 |
return;
|
305 |
}
|
306 |
|
307 |
-
|
308 |
-
|
309 |
-
$cacheInfo = $cache->getDatastoreInfo();
|
310 |
-
$filename = $cacheInfo['fpath'];
|
311 |
-
$response['path'] = basename($filename);
|
312 |
-
$response['ok'] = false;
|
313 |
-
|
314 |
-
if (!file_exists($filename)) {
|
315 |
-
$response['error'] = 'cache does not exists';
|
316 |
-
} elseif (!is_writable($filename)) {
|
317 |
-
$response['error'] = 'cache is not resetable';
|
318 |
-
} else {
|
319 |
-
$response['ok'] = (bool) @unlink($filename);
|
320 |
-
}
|
321 |
|
322 |
-
wp_send_json(
|
323 |
}
|
324 |
}
|
64 |
|
65 |
$response = array();
|
66 |
$response['count'] = 0;
|
67 |
+
$response['status'] = '';
|
68 |
$response['content'] = '';
|
69 |
+
$response['queueSize'] = 0;
|
70 |
+
$response['pagination'] = '';
|
71 |
$response['selfhosting'] = false;
|
72 |
|
73 |
+
/* initialize the values for the pagination */
|
74 |
$maxPerPage = SUCURISCAN_AUDITLOGS_PER_PAGE;
|
75 |
$pageNumber = SucuriScanTemplate::pageNumber();
|
76 |
$logsLimit = ($pageNumber * $maxPerPage);
|
84 |
/* API call if cache is invalid. */
|
85 |
if (!$auditlogs || $pageNumber !== 1) {
|
86 |
ob_start();
|
87 |
+
$start = microtime(true);
|
88 |
$cacheTheResponse = true;
|
89 |
$auditlogs = SucuriScanAPI::getAuditLogs($logsLimit);
|
90 |
+
$errors = ob_get_contents(); /* capture errors */
|
91 |
+
$duration = microtime(true) - $start;
|
92 |
ob_end_clean();
|
93 |
+
|
94 |
+
/* report latency in the API calls */
|
95 |
+
$response['status'] = !is_array($auditlogs)
|
96 |
+
? __('AuditLogsNoAPI', SUCURISCAN_TEXTDOMAIN)
|
97 |
+
: sprintf('API %s secs', round($duration, 4));
|
98 |
}
|
99 |
|
100 |
+
/* stop everything and report errors */
|
101 |
if (!empty($errors)) {
|
102 |
+
$response['content'] .= $errors;
|
|
|
|
|
103 |
}
|
104 |
|
105 |
/* Cache the data for sometime. */
|
107 |
$cache->add('response', $auditlogs);
|
108 |
}
|
109 |
|
110 |
+
/* merge the logs from the queue system */
|
111 |
+
if ($queuelogs = SucuriScanAPI::getAuditLogsFromQueue()) {
|
112 |
+
if (!$auditlogs) {
|
113 |
+
$auditlogs = $queuelogs;
|
114 |
+
} else {
|
115 |
+
$auditlogs['total_entries'] += $queuelogs['total_entries'];
|
116 |
+
$auditlogs['output'] = array_merge(
|
117 |
+
$queuelogs['output'],
|
118 |
+
$auditlogs['output']
|
119 |
+
);
|
120 |
+
$auditlogs['output_data'] = array_merge(
|
121 |
+
$queuelogs['output_data'],
|
122 |
+
$auditlogs['output_data']
|
123 |
+
);
|
124 |
+
}
|
125 |
}
|
126 |
|
127 |
if ($auditlogs) {
|
216 |
$response['content'] = __('NoLogs', SUCURISCAN_TEXTDOMAIN);
|
217 |
}
|
218 |
|
219 |
+
$cache = new SucuriScanCache('auditqueue');
|
220 |
+
$finfo = $cache->getDatastoreInfo();
|
221 |
+
$events = $cache->getAll();
|
222 |
+
$response['queueSize'] = count($events);
|
223 |
+
|
224 |
wp_send_json($response, 200);
|
225 |
}
|
226 |
|
314 |
}
|
315 |
|
316 |
/**
|
317 |
+
* Send the logs from the queue to the API.
|
318 |
*
|
319 |
* @codeCoverageIgnore - Notice that there is a test case that covers this
|
320 |
* code, but since the WP-Send-JSON method uses die() to stop any further
|
322 |
* with a missing line in the coverage. Since the test case takes care of
|
323 |
* the functionality of this code we will assume that it is fully covered.
|
324 |
*/
|
325 |
+
public static function ajaxAuditLogsSendLogs()
|
326 |
{
|
327 |
+
if (SucuriScanRequest::post('form_action') !== 'auditlogs_send_logs') {
|
328 |
return;
|
329 |
}
|
330 |
|
331 |
+
/* blocking; might take a while */
|
332 |
+
SucuriScanEvent::sendLogsFromQueue();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
333 |
|
334 |
+
wp_send_json(array('ok' => true), 200);
|
335 |
}
|
336 |
}
|
src/cache.lib.php
CHANGED
@@ -81,7 +81,7 @@ class SucuriScanCache extends SucuriScan
|
|
81 |
*
|
82 |
* @return array Default attributes for every datastore file.
|
83 |
*/
|
84 |
-
|
85 |
{
|
86 |
$attrs = array(
|
87 |
'datastore' => $this->datastore,
|
@@ -135,32 +135,53 @@ class SucuriScanCache extends SucuriScan
|
|
135 |
return false;
|
136 |
}
|
137 |
|
138 |
-
$filename = 'sucuri-' . $this->datastore . '.php';
|
139 |
-
$
|
140 |
-
$folder_path = dirname($file_path);
|
141 |
|
142 |
-
|
143 |
-
|
144 |
-
@mkdir($folder_path, 0755, true);
|
145 |
}
|
146 |
|
147 |
-
|
148 |
-
|
149 |
-
@file_put_contents($file_path, $this->datastoreInfo());
|
150 |
}
|
151 |
|
152 |
-
return $
|
153 |
}
|
154 |
|
155 |
/**
|
156 |
* Check whether a key has a valid name or not.
|
157 |
*
|
|
|
|
|
|
|
|
|
158 |
* @param string $key Unique name for the data.
|
159 |
-
* @return bool
|
160 |
*/
|
161 |
private function validKeyName($key = '')
|
162 |
{
|
163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
}
|
165 |
|
166 |
/**
|
@@ -171,18 +192,20 @@ class SucuriScanCache extends SucuriScan
|
|
171 |
*/
|
172 |
private function saveNewEntries($finfo = array())
|
173 |
{
|
174 |
-
|
|
|
|
|
175 |
|
176 |
-
|
|
|
|
|
177 |
foreach ($finfo['entries'] as $key => $data) {
|
178 |
-
|
179 |
-
|
180 |
-
$data_string .= sprintf("%s:%s\n", $key, $data);
|
181 |
-
}
|
182 |
}
|
183 |
}
|
184 |
|
185 |
-
return
|
186 |
}
|
187 |
|
188 |
/**
|
@@ -191,28 +214,35 @@ class SucuriScanCache extends SucuriScan
|
|
191 |
* be merged automatically.
|
192 |
*
|
193 |
* @param bool $assoc Force object to array conversion.
|
|
|
194 |
* @return array Rainbow table with the key names and decoded values.
|
195 |
*/
|
196 |
-
private function getDatastoreContent($assoc = false)
|
197 |
{
|
198 |
$object = array();
|
199 |
$object['info'] = array();
|
200 |
$object['entries'] = array();
|
201 |
-
$header = '/^\/\/ ([a-z_]+)=(.*);$/';
|
202 |
-
$content = '/^([0-9a-zA-Z_]+):(.+)/';
|
203 |
|
204 |
if ($lines = SucuriScanFileInfo::fileLines($this->datastore_path)) {
|
205 |
foreach ($lines as $line) {
|
206 |
-
if (
|
207 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
continue;
|
209 |
}
|
210 |
|
211 |
-
if (
|
212 |
-
|
213 |
-
|
214 |
-
@json_decode($match[2], $assoc);
|
215 |
-
}
|
216 |
}
|
217 |
}
|
218 |
}
|
@@ -234,7 +264,7 @@ class SucuriScanCache extends SucuriScan
|
|
234 |
*/
|
235 |
public function getDatastoreInfo()
|
236 |
{
|
237 |
-
$finfo = $this->getDatastoreContent();
|
238 |
|
239 |
if (empty($finfo['info'])) {
|
240 |
return false;
|
@@ -273,7 +303,8 @@ class SucuriScanCache extends SucuriScan
|
|
273 |
public function dataHasExpired($lifetime = 0, $finfo = null)
|
274 |
{
|
275 |
if (is_null($finfo)) {
|
276 |
-
$
|
|
|
277 |
}
|
278 |
|
279 |
if ($lifetime > 0 && !empty($finfo['info'])) {
|
@@ -315,11 +346,10 @@ class SucuriScanCache extends SucuriScan
|
|
315 |
return self::throwException('Invalid cache key name');
|
316 |
}
|
317 |
|
318 |
-
$finfo = $this->
|
319 |
-
|
320 |
-
$finfo['entries'][$key] = $data;
|
321 |
|
322 |
-
return
|
323 |
}
|
324 |
|
325 |
/**
|
@@ -403,6 +433,20 @@ class SucuriScanCache extends SucuriScan
|
|
403 |
return $this->saveNewEntries($finfo);
|
404 |
}
|
405 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
406 |
/**
|
407 |
* Remove all the entries from the datastore file.
|
408 |
*
|
@@ -410,12 +454,8 @@ class SucuriScanCache extends SucuriScan
|
|
410 |
*/
|
411 |
public function flush()
|
412 |
{
|
413 |
-
$
|
414 |
-
|
415 |
-
if (array_key_exists('entries', $finfo)) {
|
416 |
-
$finfo['entries'] = array();
|
417 |
-
}
|
418 |
|
419 |
-
return $this->
|
420 |
}
|
421 |
}
|
81 |
*
|
82 |
* @return array Default attributes for every datastore file.
|
83 |
*/
|
84 |
+
public function datastoreDefaultInfo()
|
85 |
{
|
86 |
$attrs = array(
|
87 |
'datastore' => $this->datastore,
|
135 |
return false;
|
136 |
}
|
137 |
|
138 |
+
$filename = $this->dataStorePath('sucuri-' . $this->datastore . '.php');
|
139 |
+
$directory = dirname($filename); /* create directory if necessary */
|
|
|
140 |
|
141 |
+
if (!file_exists($directory)) {
|
142 |
+
@mkdir($directory, 0755, true);
|
|
|
143 |
}
|
144 |
|
145 |
+
if (!file_exists($filename) && is_writable($directory) && $auto_create) {
|
146 |
+
@file_put_contents($filename, $this->datastoreInfo());
|
|
|
147 |
}
|
148 |
|
149 |
+
return $filename;
|
150 |
}
|
151 |
|
152 |
/**
|
153 |
* Check whether a key has a valid name or not.
|
154 |
*
|
155 |
+
* WARNING: Instead of using a regular expression to match the format of the
|
156 |
+
* key we will use a primitive string transformation technique to reduce the
|
157 |
+
* execution time, regular expressions are significantly slow.
|
158 |
+
*
|
159 |
* @param string $key Unique name for the data.
|
160 |
+
* @return bool True if the key is valid, false otherwise.
|
161 |
*/
|
162 |
private function validKeyName($key = '')
|
163 |
{
|
164 |
+
$result = true;
|
165 |
+
$length = strlen($key);
|
166 |
+
$allowed = array(
|
167 |
+
/* preg_match('/^([0-9a-zA-Z_]+)$/', $key) */
|
168 |
+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
169 |
+
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
170 |
+
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
171 |
+
'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
|
172 |
+
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
173 |
+
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
174 |
+
'Y', 'Z', '_',
|
175 |
+
);
|
176 |
+
|
177 |
+
for ($i = 0; $i < $length; $i++) {
|
178 |
+
if (!in_array($key[$i], $allowed)) {
|
179 |
+
$result = false;
|
180 |
+
break;
|
181 |
+
}
|
182 |
+
}
|
183 |
+
|
184 |
+
return $result;
|
185 |
}
|
186 |
|
187 |
/**
|
192 |
*/
|
193 |
private function saveNewEntries($finfo = array())
|
194 |
{
|
195 |
+
if (!$finfo) {
|
196 |
+
return false;
|
197 |
+
}
|
198 |
|
199 |
+
$metadata = $this->datastoreInfo($finfo);
|
200 |
+
|
201 |
+
if (@file_put_contents($this->datastore_path, $metadata)) {
|
202 |
foreach ($finfo['entries'] as $key => $data) {
|
203 |
+
$line = sprintf("%s:%s\n", $key, json_encode($data));
|
204 |
+
@file_put_contents($this->datastore_path, $line, FILE_APPEND);
|
|
|
|
|
205 |
}
|
206 |
}
|
207 |
|
208 |
+
return true;
|
209 |
}
|
210 |
|
211 |
/**
|
214 |
* be merged automatically.
|
215 |
*
|
216 |
* @param bool $assoc Force object to array conversion.
|
217 |
+
* @param bool $onlyInfo Returns the cache headers and no content.
|
218 |
* @return array Rainbow table with the key names and decoded values.
|
219 |
*/
|
220 |
+
private function getDatastoreContent($assoc = false, $onlyInfo = false)
|
221 |
{
|
222 |
$object = array();
|
223 |
$object['info'] = array();
|
224 |
$object['entries'] = array();
|
|
|
|
|
225 |
|
226 |
if ($lines = SucuriScanFileInfo::fileLines($this->datastore_path)) {
|
227 |
foreach ($lines as $line) {
|
228 |
+
if (strpos($line, "//\x20") === 0
|
229 |
+
&& strpos($line, '=') !== false
|
230 |
+
&& $line[strlen($line)-1] === ';'
|
231 |
+
) {
|
232 |
+
$section = substr($line, 3, strlen($line)-4);
|
233 |
+
list($header, $value) = explode('=', $section, 2);
|
234 |
+
$object['info'][$header] = $value;
|
235 |
+
continue;
|
236 |
+
}
|
237 |
+
|
238 |
+
/* skip content */
|
239 |
+
if ($onlyInfo) {
|
240 |
continue;
|
241 |
}
|
242 |
|
243 |
+
if (strpos($line, ':') !== false) {
|
244 |
+
list($keyname, $value) = explode(':', $line, 2);
|
245 |
+
$object['entries'][$keyname] = @json_decode($value, $assoc);
|
|
|
|
|
246 |
}
|
247 |
}
|
248 |
}
|
264 |
*/
|
265 |
public function getDatastoreInfo()
|
266 |
{
|
267 |
+
$finfo = $this->getDatastoreContent(false, true);
|
268 |
|
269 |
if (empty($finfo['info'])) {
|
270 |
return false;
|
303 |
public function dataHasExpired($lifetime = 0, $finfo = null)
|
304 |
{
|
305 |
if (is_null($finfo)) {
|
306 |
+
$meta = $this->getDatastoreInfo();
|
307 |
+
$finfo = array('info' => $meta);
|
308 |
}
|
309 |
|
310 |
if ($lifetime > 0 && !empty($finfo['info'])) {
|
346 |
return self::throwException('Invalid cache key name');
|
347 |
}
|
348 |
|
349 |
+
$finfo = $this->getDatastoreInfo();
|
350 |
+
$line = sprintf("%s:%s\n", $key, json_encode($data));
|
|
|
351 |
|
352 |
+
return (bool) @file_put_contents($finfo['fpath'], $line, FILE_APPEND);
|
353 |
}
|
354 |
|
355 |
/**
|
433 |
return $this->saveNewEntries($finfo);
|
434 |
}
|
435 |
|
436 |
+
/**
|
437 |
+
* Replaces the entire content of the cache file.
|
438 |
+
*
|
439 |
+
* @param array $entries New data for the cache.
|
440 |
+
* @return bool True if the cache was replaced.
|
441 |
+
*/
|
442 |
+
public function override($entries = array())
|
443 |
+
{
|
444 |
+
return $this->saveNewEntries(array(
|
445 |
+
'info' => $this->getDatastoreInfo(),
|
446 |
+
'entries' => $entries,
|
447 |
+
));
|
448 |
+
}
|
449 |
+
|
450 |
/**
|
451 |
* Remove all the entries from the datastore file.
|
452 |
*
|
454 |
*/
|
455 |
public function flush()
|
456 |
{
|
457 |
+
$filename = 'sucuri-' . $this->datastore . '.php';
|
|
|
|
|
|
|
|
|
458 |
|
459 |
+
return @unlink($this->dataStorePath($filename));
|
460 |
}
|
461 |
}
|
src/event.lib.php
CHANGED
@@ -34,7 +34,7 @@ if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) {
|
|
34 |
class SucuriScanEvent extends SucuriScan
|
35 |
{
|
36 |
/**
|
37 |
-
* Creates a cronjob to run the file system scanner
|
38 |
*
|
39 |
* Right after a fresh installation of the plugin, it will create a cronjob
|
40 |
* that will execute the first scan in the next five minutes. This scan will
|
@@ -43,23 +43,13 @@ class SucuriScanEvent extends SucuriScan
|
|
43 |
* list with the checksum of the new file list, if there are differences we
|
44 |
* will assume that someone or something modified one or more files and send
|
45 |
* an email alsert about the incident.
|
46 |
-
*
|
47 |
-
* @param bool $run_now Forces the execute of the scanner right now.
|
48 |
*/
|
49 |
-
public static function
|
50 |
{
|
51 |
-
|
52 |
-
if (SucuriScanOption::getOption(':scan_frequency') !== '_oneoff') {
|
53 |
-
$task_name = 'sucuriscan_scheduled_scan';
|
54 |
-
|
55 |
-
if (!wp_next_scheduled($task_name)) {
|
56 |
-
wp_schedule_event(time() + 10, 'twicedaily', $task_name);
|
57 |
-
}
|
58 |
|
59 |
-
|
60 |
-
|
61 |
-
wp_schedule_single_event(time() + 300, $task_name);
|
62 |
-
}
|
63 |
}
|
64 |
}
|
65 |
|
@@ -179,10 +169,38 @@ class SucuriScanEvent extends SucuriScan
|
|
179 |
* in a failure. However, this procedure depends on the ability of the plugin
|
180 |
* to write the log into the queue when the previous request failed.
|
181 |
*
|
182 |
-
* @param string $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
* @return bool True if the operation succeeded, false otherwise.
|
184 |
*/
|
185 |
-
public static function
|
186 |
{
|
187 |
/* create storage directory if necessary */
|
188 |
SucuriScanInterface::createStorageFolder();
|
@@ -191,9 +209,9 @@ class SucuriScanEvent extends SucuriScan
|
|
191 |
* Self-hosted Monitor.
|
192 |
*
|
193 |
* Send a copy of the event log to a local file, this will allow the
|
194 |
-
* administrator of the server to integrate the events monitored by the
|
195 |
-
* with a 3rd-party service like OSSEC or similar. More
|
196 |
-
* Hosting panel located in the plugin' settings page.
|
197 |
*/
|
198 |
if (function_exists('sucuriscan_selfhosting_fpath')) {
|
199 |
$monitor_fpath = sucuriscan_selfhosting_fpath();
|
@@ -204,7 +222,7 @@ class SucuriScanEvent extends SucuriScan
|
|
204 |
date('Y-m-d H:i:s'),
|
205 |
SucuriScan::getTopLevelDomain(),
|
206 |
SucuriScanOption::getOption(':account'),
|
207 |
-
$
|
208 |
);
|
209 |
@file_put_contents(
|
210 |
$monitor_fpath,
|
@@ -214,24 +232,69 @@ class SucuriScanEvent extends SucuriScan
|
|
214 |
}
|
215 |
}
|
216 |
|
|
|
217 |
if (SucuriScanOption::isEnabled(':api_service')) {
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
}
|
222 |
|
223 |
return true;
|
224 |
}
|
225 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
226 |
/**
|
227 |
* Generates an audit event log (to be sent later).
|
228 |
*
|
229 |
* @param int $severity Importance of the event that will be reported, values from one to five.
|
230 |
* @param string $message The explanation of the event.
|
231 |
-
* @param bool $internal Whether the event will be publicly visible or not.
|
232 |
* @return bool True if the event was logged in the monitoring service, false otherwise.
|
233 |
*/
|
234 |
-
private static function reportEvent($severity = 0, $message = ''
|
235 |
{
|
236 |
$user = wp_get_current_user();
|
237 |
$remote_ip = self::getRemoteAddr();
|
@@ -260,18 +323,13 @@ class SucuriScanEvent extends SucuriScan
|
|
260 |
$severity_name = $severities[$severity];
|
261 |
}
|
262 |
|
263 |
-
if ($internal === true) {
|
264 |
-
/* mark the event as internal if necessary. */
|
265 |
-
$severity_name = '@' . $severity_name;
|
266 |
-
}
|
267 |
-
|
268 |
/* remove unnecessary characters */
|
269 |
$message = strip_tags($message);
|
270 |
$message = str_replace("\r", '', $message);
|
271 |
$message = str_replace("\n", '', $message);
|
272 |
$message = str_replace("\t", '', $message);
|
273 |
|
274 |
-
return self::
|
275 |
'%s:%s %s; %s',
|
276 |
$severity_name,
|
277 |
$username,
|
@@ -284,72 +342,66 @@ class SucuriScanEvent extends SucuriScan
|
|
284 |
* Reports a debug event on the website.
|
285 |
*
|
286 |
* @param string $message Text witht the explanation of the event or action performed.
|
287 |
-
* @param bool $internal Whether the event will be publicly visible or not.
|
288 |
* @return bool Either true or false depending on the success of the operation.
|
289 |
*/
|
290 |
-
public static function reportDebugEvent($message = ''
|
291 |
{
|
292 |
-
return self::reportEvent(0, $message
|
293 |
}
|
294 |
|
295 |
/**
|
296 |
* Reports a notice event on the website.
|
297 |
*
|
298 |
* @param string $message Text witht the explanation of the event or action performed.
|
299 |
-
* @param bool $internal Whether the event will be publicly visible or not.
|
300 |
* @return bool Either true or false depending on the success of the operation.
|
301 |
*/
|
302 |
-
public static function reportNoticeEvent($message = ''
|
303 |
{
|
304 |
-
return self::reportEvent(1, $message
|
305 |
}
|
306 |
|
307 |
/**
|
308 |
* Reports a info event on the website.
|
309 |
*
|
310 |
* @param string $message Text witht the explanation of the event or action performed.
|
311 |
-
* @param bool $internal Whether the event will be publicly visible or not.
|
312 |
* @return bool Either true or false depending on the success of the operation.
|
313 |
*/
|
314 |
-
public static function reportInfoEvent($message = ''
|
315 |
{
|
316 |
-
return self::reportEvent(2, $message
|
317 |
}
|
318 |
|
319 |
/**
|
320 |
* Reports a warning event on the website.
|
321 |
*
|
322 |
* @param string $message Text witht the explanation of the event or action performed.
|
323 |
-
* @param bool $internal Whether the event will be publicly visible or not.
|
324 |
* @return bool Either true or false depending on the success of the operation.
|
325 |
*/
|
326 |
-
public static function reportWarningEvent($message = ''
|
327 |
{
|
328 |
-
return self::reportEvent(3, $message
|
329 |
}
|
330 |
|
331 |
/**
|
332 |
* Reports a error event on the website.
|
333 |
*
|
334 |
* @param string $message Text witht the explanation of the event or action performed.
|
335 |
-
* @param bool $internal Whether the event will be publicly visible or not.
|
336 |
* @return bool Either true or false depending on the success of the operation.
|
337 |
*/
|
338 |
-
public static function reportErrorEvent($message = ''
|
339 |
{
|
340 |
-
return self::reportEvent(4, $message
|
341 |
}
|
342 |
|
343 |
/**
|
344 |
* Reports a critical event on the website.
|
345 |
*
|
346 |
* @param string $message Text witht the explanation of the event or action performed.
|
347 |
-
* @param bool $internal Whether the event will be publicly visible or not.
|
348 |
* @return bool Either true or false depending on the success of the operation.
|
349 |
*/
|
350 |
-
public static function reportCriticalEvent($message = ''
|
351 |
{
|
352 |
-
return self::reportEvent(5, $message
|
353 |
}
|
354 |
|
355 |
/**
|
@@ -357,10 +409,9 @@ class SucuriScanEvent extends SucuriScan
|
|
357 |
*
|
358 |
* @param string $message Text witht the explanation of the event or action performed.
|
359 |
* @param string $action An optional text, hopefully either enabled or disabled.
|
360 |
-
* @param bool $internal Whether the event will be publicly visible or not.
|
361 |
* @return bool Either true or false depending on the success of the operation.
|
362 |
*/
|
363 |
-
public static function reportAutoEvent($message = '', $action = ''
|
364 |
{
|
365 |
$message = strip_tags($message);
|
366 |
|
@@ -370,14 +421,14 @@ class SucuriScanEvent extends SucuriScan
|
|
370 |
}
|
371 |
|
372 |
if ($action === 'enabled') {
|
373 |
-
return self::reportNoticeEvent($message
|
374 |
}
|
375 |
|
376 |
if ($action === 'disabled') {
|
377 |
-
return self::reportErrorEvent($message
|
378 |
}
|
379 |
|
380 |
-
return self::reportInfoEvent($message
|
381 |
}
|
382 |
|
383 |
/**
|
@@ -647,7 +698,7 @@ class SucuriScanEvent extends SucuriScan
|
|
647 |
}
|
648 |
}
|
649 |
|
650 |
-
$
|
651 |
'updated' => is_writable($config_path),
|
652 |
'old_keys' => $old_keys,
|
653 |
'old_keys_string' => $old_keys_string,
|
@@ -656,10 +707,10 @@ class SucuriScanEvent extends SucuriScan
|
|
656 |
'new_wpconfig' => $new_wpconfig,
|
657 |
);
|
658 |
|
659 |
-
if ($
|
660 |
@file_put_contents($config_path, $new_wpconfig, LOCK_EX);
|
661 |
}
|
662 |
|
663 |
-
return $
|
664 |
}
|
665 |
}
|
34 |
class SucuriScanEvent extends SucuriScan
|
35 |
{
|
36 |
/**
|
37 |
+
* Creates a cronjob to run the file system scanner.
|
38 |
*
|
39 |
* Right after a fresh installation of the plugin, it will create a cronjob
|
40 |
* that will execute the first scan in the next five minutes. This scan will
|
43 |
* list with the checksum of the new file list, if there are differences we
|
44 |
* will assume that someone or something modified one or more files and send
|
45 |
* an email alsert about the incident.
|
|
|
|
|
46 |
*/
|
47 |
+
public static function installScheduledTask()
|
48 |
{
|
49 |
+
$task_name = 'sucuriscan_scheduled_scan';
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
|
51 |
+
if (!wp_next_scheduled($task_name)) {
|
52 |
+
wp_schedule_event(time() + 10, 'daily', $task_name);
|
|
|
|
|
53 |
}
|
54 |
}
|
55 |
|
169 |
* in a failure. However, this procedure depends on the ability of the plugin
|
170 |
* to write the log into the queue when the previous request failed.
|
171 |
*
|
172 |
+
* @param string $message Information about the event.
|
173 |
+
* @param string $timestamp Time when the event was triggered.
|
174 |
+
* @return bool True if the event was logged, false otherwise.
|
175 |
+
*/
|
176 |
+
private static function sendLogToAPI($message = '', $timestamp = '')
|
177 |
+
{
|
178 |
+
if (empty($message)) {
|
179 |
+
return self::throwException('Event identifier cannot be empty');
|
180 |
+
}
|
181 |
+
|
182 |
+
$params = array();
|
183 |
+
$params['a'] = 'send_log';
|
184 |
+
$params['m'] = $message;
|
185 |
+
$params['time'] = $timestamp;
|
186 |
+
$args = array('timeout' => 5 /* seconds */);
|
187 |
+
|
188 |
+
$resp = SucuriScanAPI::apiCallWordpress('POST', $params, true, $args);
|
189 |
+
|
190 |
+
return (bool) (
|
191 |
+
is_array($resp)
|
192 |
+
&& array_key_exists('status', $resp)
|
193 |
+
&& intval($resp['status']) === 1
|
194 |
+
);
|
195 |
+
}
|
196 |
+
|
197 |
+
/**
|
198 |
+
* Sends the event message to a local queue system.
|
199 |
+
*
|
200 |
+
* @param string $message Information about the security event.
|
201 |
* @return bool True if the operation succeeded, false otherwise.
|
202 |
*/
|
203 |
+
public static function sendLogToQueue($message = '')
|
204 |
{
|
205 |
/* create storage directory if necessary */
|
206 |
SucuriScanInterface::createStorageFolder();
|
209 |
* Self-hosted Monitor.
|
210 |
*
|
211 |
* Send a copy of the event log to a local file, this will allow the
|
212 |
+
* administrator of the server to integrate the events monitored by the
|
213 |
+
* plugin with a 3rd-party service like OSSEC or similar. More info in
|
214 |
+
* the Self-Hosting panel located in the plugin' settings page.
|
215 |
*/
|
216 |
if (function_exists('sucuriscan_selfhosting_fpath')) {
|
217 |
$monitor_fpath = sucuriscan_selfhosting_fpath();
|
222 |
date('Y-m-d H:i:s'),
|
223 |
SucuriScan::getTopLevelDomain(),
|
224 |
SucuriScanOption::getOption(':account'),
|
225 |
+
$message
|
226 |
);
|
227 |
@file_put_contents(
|
228 |
$monitor_fpath,
|
232 |
}
|
233 |
}
|
234 |
|
235 |
+
/* enqueue the event if the API is enabled */
|
236 |
if (SucuriScanOption::isEnabled(':api_service')) {
|
237 |
+
$cache = new SucuriScanCache('auditqueue');
|
238 |
+
$key = str_replace('.', '_', microtime(true));
|
239 |
+
$written = $cache->add($key, $message);
|
240 |
}
|
241 |
|
242 |
return true;
|
243 |
}
|
244 |
|
245 |
+
/**
|
246 |
+
* Sends all the events from the queue to the API.
|
247 |
+
*/
|
248 |
+
public static function sendLogsFromQueue()
|
249 |
+
{
|
250 |
+
if (SucuriScanOption::isDisabled(':api_service')) {
|
251 |
+
return;
|
252 |
+
}
|
253 |
+
|
254 |
+
$cache = new SucuriScanCache('auditqueue');
|
255 |
+
$finfo = $cache->getDatastoreInfo();
|
256 |
+
$events = $cache->getAll();
|
257 |
+
$counter = 0;
|
258 |
+
|
259 |
+
if (!$events) {
|
260 |
+
return;
|
261 |
+
}
|
262 |
+
|
263 |
+
/* Send around 15,000 logs for maximum 30 seconds */
|
264 |
+
$maxtime = (int) SucuriScan::iniGet('max_execution_time');
|
265 |
+
$maxreqs = ($maxtime > 1) ? (500 * $maxtime) : 5000;
|
266 |
+
|
267 |
+
foreach ($events as $keyname => $message) {
|
268 |
+
$offset = strpos($keyname, '_');
|
269 |
+
$timestamp = substr($keyname, 0, $offset);
|
270 |
+
$status = self::sendLogToAPI($message, $timestamp);
|
271 |
+
|
272 |
+
if ($status !== true) {
|
273 |
+
/* API is down */
|
274 |
+
break;
|
275 |
+
}
|
276 |
+
|
277 |
+
/* dequeue event message */
|
278 |
+
unset($events[$keyname]);
|
279 |
+
$counter++;
|
280 |
+
|
281 |
+
/* avoid memory limit */
|
282 |
+
if ($counter >= $maxreqs) {
|
283 |
+
break;
|
284 |
+
}
|
285 |
+
}
|
286 |
+
|
287 |
+
$cache->override($events);
|
288 |
+
}
|
289 |
+
|
290 |
/**
|
291 |
* Generates an audit event log (to be sent later).
|
292 |
*
|
293 |
* @param int $severity Importance of the event that will be reported, values from one to five.
|
294 |
* @param string $message The explanation of the event.
|
|
|
295 |
* @return bool True if the event was logged in the monitoring service, false otherwise.
|
296 |
*/
|
297 |
+
private static function reportEvent($severity = 0, $message = '')
|
298 |
{
|
299 |
$user = wp_get_current_user();
|
300 |
$remote_ip = self::getRemoteAddr();
|
323 |
$severity_name = $severities[$severity];
|
324 |
}
|
325 |
|
|
|
|
|
|
|
|
|
|
|
326 |
/* remove unnecessary characters */
|
327 |
$message = strip_tags($message);
|
328 |
$message = str_replace("\r", '', $message);
|
329 |
$message = str_replace("\n", '', $message);
|
330 |
$message = str_replace("\t", '', $message);
|
331 |
|
332 |
+
return self::sendLogToQueue(sprintf(
|
333 |
'%s:%s %s; %s',
|
334 |
$severity_name,
|
335 |
$username,
|
342 |
* Reports a debug event on the website.
|
343 |
*
|
344 |
* @param string $message Text witht the explanation of the event or action performed.
|
|
|
345 |
* @return bool Either true or false depending on the success of the operation.
|
346 |
*/
|
347 |
+
public static function reportDebugEvent($message = '')
|
348 |
{
|
349 |
+
return self::reportEvent(0, $message);
|
350 |
}
|
351 |
|
352 |
/**
|
353 |
* Reports a notice event on the website.
|
354 |
*
|
355 |
* @param string $message Text witht the explanation of the event or action performed.
|
|
|
356 |
* @return bool Either true or false depending on the success of the operation.
|
357 |
*/
|
358 |
+
public static function reportNoticeEvent($message = '')
|
359 |
{
|
360 |
+
return self::reportEvent(1, $message);
|
361 |
}
|
362 |
|
363 |
/**
|
364 |
* Reports a info event on the website.
|
365 |
*
|
366 |
* @param string $message Text witht the explanation of the event or action performed.
|
|
|
367 |
* @return bool Either true or false depending on the success of the operation.
|
368 |
*/
|
369 |
+
public static function reportInfoEvent($message = '')
|
370 |
{
|
371 |
+
return self::reportEvent(2, $message);
|
372 |
}
|
373 |
|
374 |
/**
|
375 |
* Reports a warning event on the website.
|
376 |
*
|
377 |
* @param string $message Text witht the explanation of the event or action performed.
|
|
|
378 |
* @return bool Either true or false depending on the success of the operation.
|
379 |
*/
|
380 |
+
public static function reportWarningEvent($message = '')
|
381 |
{
|
382 |
+
return self::reportEvent(3, $message);
|
383 |
}
|
384 |
|
385 |
/**
|
386 |
* Reports a error event on the website.
|
387 |
*
|
388 |
* @param string $message Text witht the explanation of the event or action performed.
|
|
|
389 |
* @return bool Either true or false depending on the success of the operation.
|
390 |
*/
|
391 |
+
public static function reportErrorEvent($message = '')
|
392 |
{
|
393 |
+
return self::reportEvent(4, $message);
|
394 |
}
|
395 |
|
396 |
/**
|
397 |
* Reports a critical event on the website.
|
398 |
*
|
399 |
* @param string $message Text witht the explanation of the event or action performed.
|
|
|
400 |
* @return bool Either true or false depending on the success of the operation.
|
401 |
*/
|
402 |
+
public static function reportCriticalEvent($message = '')
|
403 |
{
|
404 |
+
return self::reportEvent(5, $message);
|
405 |
}
|
406 |
|
407 |
/**
|
409 |
*
|
410 |
* @param string $message Text witht the explanation of the event or action performed.
|
411 |
* @param string $action An optional text, hopefully either enabled or disabled.
|
|
|
412 |
* @return bool Either true or false depending on the success of the operation.
|
413 |
*/
|
414 |
+
public static function reportAutoEvent($message = '', $action = '')
|
415 |
{
|
416 |
$message = strip_tags($message);
|
417 |
|
421 |
}
|
422 |
|
423 |
if ($action === 'enabled') {
|
424 |
+
return self::reportNoticeEvent($message);
|
425 |
}
|
426 |
|
427 |
if ($action === 'disabled') {
|
428 |
+
return self::reportErrorEvent($message);
|
429 |
}
|
430 |
|
431 |
+
return self::reportInfoEvent($message);
|
432 |
}
|
433 |
|
434 |
/**
|
698 |
}
|
699 |
}
|
700 |
|
701 |
+
$resp = array(
|
702 |
'updated' => is_writable($config_path),
|
703 |
'old_keys' => $old_keys,
|
704 |
'old_keys_string' => $old_keys_string,
|
707 |
'new_wpconfig' => $new_wpconfig,
|
708 |
);
|
709 |
|
710 |
+
if ($resp['updated']) {
|
711 |
@file_put_contents($config_path, $new_wpconfig, LOCK_EX);
|
712 |
}
|
713 |
|
714 |
+
return $resp;
|
715 |
}
|
716 |
}
|
src/fileinfo.lib.php
CHANGED
@@ -95,7 +95,12 @@ class SucuriScanFileInfo extends SucuriScan
|
|
95 |
*/
|
96 |
public static function isSplAvailable()
|
97 |
{
|
98 |
-
return (bool) (
|
|
|
|
|
|
|
|
|
|
|
99 |
}
|
100 |
|
101 |
/**
|
@@ -180,7 +185,7 @@ class SucuriScanFileInfo extends SucuriScan
|
|
180 |
{
|
181 |
$files = array();
|
182 |
|
183 |
-
if (is_dir($directory)) {
|
184 |
$objects = array();
|
185 |
|
186 |
$this->ignored_directories = SucuriScanFSScanner::getIgnoredDirectories();
|
95 |
*/
|
96 |
public static function isSplAvailable()
|
97 |
{
|
98 |
+
return (bool) (
|
99 |
+
class_exists('SplFileObject')
|
100 |
+
&& class_exists('FilesystemIterator')
|
101 |
+
&& class_exists('RecursiveIteratorIterator')
|
102 |
+
&& class_exists('RecursiveDirectoryIterator')
|
103 |
+
);
|
104 |
}
|
105 |
|
106 |
/**
|
185 |
{
|
186 |
$files = array();
|
187 |
|
188 |
+
if (is_dir($directory) && self::isSplAvailable()) {
|
189 |
$objects = array();
|
190 |
|
191 |
$this->ignored_directories = SucuriScanFSScanner::getIgnoredDirectories();
|
src/firewall.lib.php
CHANGED
@@ -297,9 +297,11 @@ class SucuriScanFirewall extends SucuriScanAPI
|
|
297 |
*/
|
298 |
public static function auditlogsPage()
|
299 |
{
|
300 |
-
$date = date('Y-m-d');
|
301 |
$params = array();
|
302 |
|
|
|
|
|
|
|
303 |
$params['AuditLogs.DateYears'] = self::dates('years', $date);
|
304 |
$params['AuditLogs.DateMonths'] = self::dates('months', $date);
|
305 |
$params['AuditLogs.DateDays'] = self::dates('days', $date);
|
297 |
*/
|
298 |
public static function auditlogsPage()
|
299 |
{
|
|
|
300 |
$params = array();
|
301 |
|
302 |
+
/* logs are available after 24 hours */
|
303 |
+
$date = date('Y-m-d', strtotime('-1 day'));
|
304 |
+
|
305 |
$params['AuditLogs.DateYears'] = self::dates('years', $date);
|
306 |
$params['AuditLogs.DateMonths'] = self::dates('months', $date);
|
307 |
$params['AuditLogs.DateDays'] = self::dates('days', $date);
|
src/globals.php
CHANGED
@@ -111,14 +111,38 @@ if (defined('SUCURISCAN')) {
|
|
111 |
{
|
112 |
global $locale;
|
113 |
|
114 |
-
$
|
115 |
'%s/languages/%s-%s.po',
|
116 |
SUCURISCAN_PLUGIN_PATH,
|
117 |
SUCURISCAN_TEXTDOMAIN,
|
118 |
$locale
|
119 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
-
|
|
|
122 |
$locale = 'en_US';
|
123 |
setlocale(LC_ALL, 'en_US');
|
124 |
}
|
@@ -203,7 +227,6 @@ if (defined('SUCURISCAN')) {
|
|
203 |
add_action('switch_theme', 'SucuriScanHook::hookThemeSwitch', 50, 5);
|
204 |
add_action('transition_post_status', 'SucuriScanHook::hookPostStatus', 50, 3);
|
205 |
add_action('user_register', 'SucuriScanHook::hookUserRegister', 50, 5);
|
206 |
-
add_action('wp_insert_comment', 'SucuriScanHook::hookCommentInsert', 50, 5);
|
207 |
add_action('wp_login', 'SucuriScanHook::hookLoginSuccess', 50, 5);
|
208 |
add_action('wp_login_failed', 'SucuriScanHook::hookLoginFailure', 50, 5);
|
209 |
add_action('wp_trash_post', 'SucuriScanHook::hookPostTrash', 50, 5);
|
111 |
{
|
112 |
global $locale;
|
113 |
|
114 |
+
$pofile = sprintf(
|
115 |
'%s/languages/%s-%s.po',
|
116 |
SUCURISCAN_PLUGIN_PATH,
|
117 |
SUCURISCAN_TEXTDOMAIN,
|
118 |
$locale
|
119 |
);
|
120 |
+
$mofile = sprintf(
|
121 |
+
'%s/languages/%s-%s.mo',
|
122 |
+
SUCURISCAN_PLUGIN_PATH,
|
123 |
+
SUCURISCAN_TEXTDOMAIN,
|
124 |
+
$locale
|
125 |
+
);
|
126 |
+
|
127 |
+
/* attempt to import the English POT file into LOCALE */
|
128 |
+
if (!file_exists($pofile) || !file_exists($mofile)) {
|
129 |
+
$en_pofile = sprintf(
|
130 |
+
'%s/languages/%s-en_US.po',
|
131 |
+
SUCURISCAN_PLUGIN_PATH,
|
132 |
+
SUCURISCAN_TEXTDOMAIN
|
133 |
+
);
|
134 |
+
$en_mofile = sprintf(
|
135 |
+
'%s/languages/%s-en_US.mo',
|
136 |
+
SUCURISCAN_PLUGIN_PATH,
|
137 |
+
SUCURISCAN_TEXTDOMAIN
|
138 |
+
);
|
139 |
+
|
140 |
+
@copy($en_pofile, $pofile);
|
141 |
+
@copy($en_mofile, $mofile);
|
142 |
+
}
|
143 |
|
144 |
+
/* fallback to English on language import failure */
|
145 |
+
if (!file_exists($pofile) || !file_exists($mofile)) {
|
146 |
$locale = 'en_US';
|
147 |
setlocale(LC_ALL, 'en_US');
|
148 |
}
|
227 |
add_action('switch_theme', 'SucuriScanHook::hookThemeSwitch', 50, 5);
|
228 |
add_action('transition_post_status', 'SucuriScanHook::hookPostStatus', 50, 3);
|
229 |
add_action('user_register', 'SucuriScanHook::hookUserRegister', 50, 5);
|
|
|
230 |
add_action('wp_login', 'SucuriScanHook::hookLoginSuccess', 50, 5);
|
231 |
add_action('wp_login_failed', 'SucuriScanHook::hookLoginFailure', 50, 5);
|
232 |
add_action('wp_trash_post', 'SucuriScanHook::hookPostTrash', 50, 5);
|
src/hook.lib.php
CHANGED
@@ -67,51 +67,6 @@ class SucuriScanHook extends SucuriScanEvent
|
|
67 |
self::notifyEvent('post_publication', $message);
|
68 |
}
|
69 |
|
70 |
-
/**
|
71 |
-
* Fires immediately after a comment is inserted into the database.
|
72 |
-
*
|
73 |
-
* The action comment-post can also be used to track the insertion of data in
|
74 |
-
* the comments table, but this only returns the identifier of the new entry in
|
75 |
-
* the database and the status (approved, not approved, spam). The WP-Insert-
|
76 |
-
* Comment action returns the same identifier and additionally the full data set
|
77 |
-
* with the comment information.
|
78 |
-
*
|
79 |
-
* @see https://codex.wordpress.org/Plugin_API/Action_Reference/wp_insert_comment
|
80 |
-
* @see https://codex.wordpress.org/Plugin_API/Action_Reference/comment_post
|
81 |
-
*
|
82 |
-
* @param int $id The comment identifier.
|
83 |
-
* @param object $comment The comment object.
|
84 |
-
*/
|
85 |
-
public static function hookCommentInsert($id = 0, $comment = null)
|
86 |
-
{
|
87 |
-
if (is_object($comment)
|
88 |
-
&& property_exists($comment, 'comment_ID')
|
89 |
-
&& property_exists($comment, 'comment_agent')
|
90 |
-
&& property_exists($comment, 'comment_author_IP')
|
91 |
-
&& SucuriScanOption::isEnabled(':comment_monitor')
|
92 |
-
) {
|
93 |
-
$data_set = array(
|
94 |
-
'id' => $comment->comment_ID,
|
95 |
-
'post_id' => $comment->comment_post_ID,
|
96 |
-
'user_id' => $comment->user_id,
|
97 |
-
'parent' => $comment->comment_parent,
|
98 |
-
'approved' => $comment->comment_approved,
|
99 |
-
'remote_addr' => $comment->comment_author_IP,
|
100 |
-
'author_email' => $comment->comment_author_email,
|
101 |
-
'date' => $comment->comment_date,
|
102 |
-
'content' => $comment->comment_content,
|
103 |
-
'user_agent' => $comment->comment_agent,
|
104 |
-
);
|
105 |
-
$message = base64_encode(json_encode($data_set));
|
106 |
-
self::reportNoticeEvent('Base64:' . $message, true);
|
107 |
-
}
|
108 |
-
}
|
109 |
-
|
110 |
-
// TODO: Log when the comment status is modified: wp_set_comment_status
|
111 |
-
// TODO: Log when the comment data is modified: edit_comment
|
112 |
-
// TODO: Log when the comment is going to be deleted: delete_comment, trash_comment
|
113 |
-
// TODO: Log when the comment is finally deleted: deleted_comment, trashed_comment
|
114 |
-
// TODO: Log when the comment is closed: comment_closed
|
115 |
// TODO: Detect auto updates in core, themes, and plugin files.
|
116 |
|
117 |
/**
|
@@ -620,6 +575,11 @@ class SucuriScanHook extends SucuriScanEvent
|
|
620 |
return self::throwException('Ignore corrupted post data');
|
621 |
}
|
622 |
|
|
|
|
|
|
|
|
|
|
|
623 |
$post_type = 'post'; /* either post or page */
|
624 |
|
625 |
if (property_exists($post, 'post_type')) {
|
67 |
self::notifyEvent('post_publication', $message);
|
68 |
}
|
69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
// TODO: Detect auto updates in core, themes, and plugin files.
|
71 |
|
72 |
/**
|
575 |
return self::throwException('Ignore corrupted post data');
|
576 |
}
|
577 |
|
578 |
+
/* ignore; the same */
|
579 |
+
if ($old === $new) {
|
580 |
+
return;
|
581 |
+
}
|
582 |
+
|
583 |
$post_type = 'post'; /* either post or page */
|
584 |
|
585 |
if (property_exists($post, 'post_type')) {
|
src/integrity.lib.php
CHANGED
@@ -119,45 +119,54 @@ class SucuriScanIntegrity
|
|
119 |
|
120 |
foreach ((array) $core_files as $file_meta) {
|
121 |
if (strpos($file_meta, '@')) {
|
122 |
-
@list($status_type, $file_path) =
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
$files_affected[] = $full_path;
|
152 |
-
|
|
|
|
|
|
|
153 |
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
}
|
159 |
-
break;
|
160 |
}
|
|
|
161 |
}
|
162 |
}
|
163 |
}
|
119 |
|
120 |
foreach ((array) $core_files as $file_meta) {
|
121 |
if (strpos($file_meta, '@')) {
|
122 |
+
@list($status_type, $file_path) = explode('@', $file_meta, 2);
|
123 |
+
|
124 |
+
if (!$file_path || !$status_type) {
|
125 |
+
continue;
|
126 |
+
}
|
127 |
+
|
128 |
+
$full_path = ABSPATH . '/' . $file_path;
|
129 |
+
|
130 |
+
if ($action === 'fixed' && (
|
131 |
+
$status_type === 'added'
|
132 |
+
|| $status_type === 'removed'
|
133 |
+
|| $status_type === 'modified'
|
134 |
+
)) {
|
135 |
+
$cache_key = md5($file_path);
|
136 |
+
$cache_value = array(
|
137 |
+
'file_path' => $file_path,
|
138 |
+
'file_status' => $status_type,
|
139 |
+
'ignored_at' => time(),
|
140 |
+
);
|
141 |
+
$cached = $cache->add($cache_key, $cache_value);
|
142 |
+
$files_processed += ($cached ? 1 : 0);
|
143 |
+
$files_affected[] = $full_path;
|
144 |
+
continue;
|
145 |
+
}
|
146 |
+
|
147 |
+
if ($action === 'restore' && (
|
148 |
+
$status_type === 'removed'
|
149 |
+
|| $status_type === 'modified'
|
150 |
+
)) {
|
151 |
+
if ($content = SucuriScanAPI::getOriginalCoreFile($file_path)) {
|
152 |
+
$basedir = dirname($full_path);
|
153 |
+
@mkdir($basedir, 0755, true);
|
154 |
+
|
155 |
+
if (file_exists($basedir)) {
|
156 |
+
$restored = @file_put_contents($full_path, $content);
|
157 |
+
$files_processed += ($restored ? 1 : 0);
|
158 |
$files_affected[] = $full_path;
|
159 |
+
}
|
160 |
+
}
|
161 |
+
continue;
|
162 |
+
}
|
163 |
|
164 |
+
if ($action === 'delete' && $status_type === 'added') {
|
165 |
+
if (@unlink($full_path)) {
|
166 |
+
$files_processed += 1;
|
167 |
+
$files_affected[] = $full_path;
|
|
|
|
|
168 |
}
|
169 |
+
continue;
|
170 |
}
|
171 |
}
|
172 |
}
|
src/interface.lib.php
CHANGED
@@ -37,14 +37,12 @@ class SucuriScanInterface
|
|
37 |
*/
|
38 |
public static function initialize()
|
39 |
{
|
40 |
-
|
41 |
-
|
42 |
-
) {
|
43 |
$_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
|
44 |
$_SERVER['REMOTE_ADDR'] = SucuriScan::getRemoteAddr();
|
45 |
}
|
46 |
-
|
47 |
-
SucuriScanEvent::scheduleTask(false);
|
48 |
}
|
49 |
|
50 |
/**
|
@@ -189,11 +187,30 @@ class SucuriScanInterface
|
|
189 |
*/
|
190 |
public static function noticeAfterUpdate()
|
191 |
{
|
|
|
|
|
|
|
192 |
/* use simple comparison to force type cast. */
|
193 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
return;
|
195 |
}
|
196 |
|
|
|
|
|
|
|
197 |
/**
|
198 |
* Suggest re-activation of the API communication.
|
199 |
*
|
@@ -218,9 +235,6 @@ class SucuriScanInterface
|
|
218 |
* @date Featured added at - May 01, 2017
|
219 |
*/
|
220 |
self::info(__('NewsletterInvitation', SUCURISCAN_TEXTDOMAIN));
|
221 |
-
|
222 |
-
/* update the version number in the plugin settings. */
|
223 |
-
SucuriScanOption::updateOption(':plugin_version', SUCURISCAN_VERSION);
|
224 |
}
|
225 |
|
226 |
/**
|
37 |
*/
|
38 |
public static function initialize()
|
39 |
{
|
40 |
+
SucuriScanEvent::installScheduledTask();
|
41 |
+
|
42 |
+
if (SucuriScan::supportReverseProxy() || SucuriScan::isBehindFirewall()) {
|
43 |
$_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
|
44 |
$_SERVER['REMOTE_ADDR'] = SucuriScan::getRemoteAddr();
|
45 |
}
|
|
|
|
|
46 |
}
|
47 |
|
48 |
/**
|
187 |
*/
|
188 |
public static function noticeAfterUpdate()
|
189 |
{
|
190 |
+
/* get version of the plugin that was previously installed */
|
191 |
+
$version = SucuriScanOption::getOption(':plugin_version');
|
192 |
+
|
193 |
/* use simple comparison to force type cast. */
|
194 |
+
if (headers_sent() || $version == SUCURISCAN_VERSION) {
|
195 |
+
return;
|
196 |
+
}
|
197 |
+
|
198 |
+
if (!is_writable(SucuriScanOption::optionsFilePath())) {
|
199 |
+
/**
|
200 |
+
* Stop if the settings file is not writable.
|
201 |
+
*
|
202 |
+
* In some cases where the settings file is not writable, or for
|
203 |
+
* some reason the option cannot be updated, the alerts below will
|
204 |
+
* be rendered all the time, to avoid unnecessary complains from
|
205 |
+
* the website owners we will not display the alerts if the option
|
206 |
+
* cannot be updated.
|
207 |
+
*/
|
208 |
return;
|
209 |
}
|
210 |
|
211 |
+
/* update the version number in the plugin settings. */
|
212 |
+
SucuriScanOption::updateOption(':plugin_version', SUCURISCAN_VERSION);
|
213 |
+
|
214 |
/**
|
215 |
* Suggest re-activation of the API communication.
|
216 |
*
|
235 |
* @date Featured added at - May 01, 2017
|
236 |
*/
|
237 |
self::info(__('NewsletterInvitation', SUCURISCAN_TEXTDOMAIN));
|
|
|
|
|
|
|
238 |
}
|
239 |
|
240 |
/**
|
src/lastlogins-loggedin.php
CHANGED
@@ -45,7 +45,7 @@ function sucuriscan_loggedin_users_panel()
|
|
45 |
'LoggedInUsers.UserEmail' => $logged_in_user['user_email'],
|
46 |
'LoggedInUsers.LastActivity' => $logged_in_user['last_activity_datetime'],
|
47 |
'LoggedInUsers.Registered' => $logged_in_user['user_registered_datetime'],
|
48 |
-
'LoggedInUsers.
|
49 |
));
|
50 |
}
|
51 |
}
|
45 |
'LoggedInUsers.UserEmail' => $logged_in_user['user_email'],
|
46 |
'LoggedInUsers.LastActivity' => $logged_in_user['last_activity_datetime'],
|
47 |
'LoggedInUsers.Registered' => $logged_in_user['user_registered_datetime'],
|
48 |
+
'LoggedInUsers.RemoteAddr' => $logged_in_user['remote_addr'],
|
49 |
));
|
50 |
}
|
51 |
}
|
src/lastlogins.php
CHANGED
@@ -232,9 +232,7 @@ if (!function_exists('sucuri_set_lastlogin')) {
|
|
232 |
*/
|
233 |
function sucuriscan_set_lastlogin($user_login = '')
|
234 |
{
|
235 |
-
$
|
236 |
-
|
237 |
-
if ($datastore_filepath) {
|
238 |
$current_user = get_user_by('login', $user_login);
|
239 |
$remote_addr = SucuriScan::getRemoteAddr();
|
240 |
|
@@ -247,7 +245,7 @@ if (!function_exists('sucuri_set_lastlogin')) {
|
|
247 |
);
|
248 |
|
249 |
@file_put_contents(
|
250 |
-
$
|
251 |
json_encode($login_info) . "\n",
|
252 |
FILE_APPEND
|
253 |
);
|
232 |
*/
|
233 |
function sucuriscan_set_lastlogin($user_login = '')
|
234 |
{
|
235 |
+
if ($filename = sucuriscan_lastlogins_datastore_is_writable()) {
|
|
|
|
|
236 |
$current_user = get_user_by('login', $user_login);
|
237 |
$remote_addr = SucuriScan::getRemoteAddr();
|
238 |
|
245 |
);
|
246 |
|
247 |
@file_put_contents(
|
248 |
+
$filename,
|
249 |
json_encode($login_info) . "\n",
|
250 |
FILE_APPEND
|
251 |
);
|
src/option.lib.php
CHANGED
@@ -55,7 +55,6 @@ class SucuriScanOption extends SucuriScanRequest
|
|
55 |
'sucuriscan_api_protocol' => 'https',
|
56 |
'sucuriscan_api_service' => 'enabled',
|
57 |
'sucuriscan_cloudproxy_apikey' => '',
|
58 |
-
'sucuriscan_comment_monitor' => 'disabled',
|
59 |
'sucuriscan_diff_utility' => 'disabled',
|
60 |
'sucuriscan_dns_lookups' => 'enabled',
|
61 |
'sucuriscan_email_subject' => '',
|
@@ -93,10 +92,8 @@ class SucuriScanOption extends SucuriScanRequest
|
|
93 |
'sucuriscan_notify_widget_deleted' => 'disabled',
|
94 |
'sucuriscan_plugin_version' => '0.0',
|
95 |
'sucuriscan_prettify_mails' => 'disabled',
|
96 |
-
'sucuriscan_request_timeout' => 15,
|
97 |
'sucuriscan_revproxy' => 'disabled',
|
98 |
'sucuriscan_runtime' => 0,
|
99 |
-
'sucuriscan_scan_frequency' => 'twicedaily',
|
100 |
'sucuriscan_selfhosting_fpath' => '',
|
101 |
'sucuriscan_selfhosting_monitor' => 'disabled',
|
102 |
'sucuriscan_site_version' => '0.0',
|
55 |
'sucuriscan_api_protocol' => 'https',
|
56 |
'sucuriscan_api_service' => 'enabled',
|
57 |
'sucuriscan_cloudproxy_apikey' => '',
|
|
|
58 |
'sucuriscan_diff_utility' => 'disabled',
|
59 |
'sucuriscan_dns_lookups' => 'enabled',
|
60 |
'sucuriscan_email_subject' => '',
|
92 |
'sucuriscan_notify_widget_deleted' => 'disabled',
|
93 |
'sucuriscan_plugin_version' => '0.0',
|
94 |
'sucuriscan_prettify_mails' => 'disabled',
|
|
|
95 |
'sucuriscan_revproxy' => 'disabled',
|
96 |
'sucuriscan_runtime' => 0,
|
|
|
97 |
'sucuriscan_selfhosting_fpath' => '',
|
98 |
'sucuriscan_selfhosting_monitor' => 'disabled',
|
99 |
'sucuriscan_site_version' => '0.0',
|
src/pagehandler.php
CHANGED
@@ -117,15 +117,13 @@ function sucuriscan_settings_page()
|
|
117 |
$params['Settings.General.ApiKey'] = sucuriscan_settings_general_apikey($nonce);
|
118 |
$params['Settings.General.DataStorage'] = sucuriscan_settings_general_datastorage();
|
119 |
$params['Settings.General.SelfHosting'] = sucuriscan_settings_general_selfhosting($nonce);
|
120 |
-
$params['Settings.General.Cronjobs'] = sucuriscan_settings_general_cronjobs();
|
121 |
$params['Settings.General.ReverseProxy'] = sucuriscan_settings_general_reverseproxy($nonce);
|
122 |
$params['Settings.General.IPDiscoverer'] = sucuriscan_settings_general_ipdiscoverer($nonce);
|
123 |
-
$params['Settings.General.CommentMonitor'] = sucuriscan_settings_general_commentmonitor($nonce);
|
124 |
$params['Settings.General.AuditLogStats'] = sucuriscan_settings_general_auditlogstats($nonce);
|
125 |
$params['Settings.General.ImportExport'] = sucuriscan_settings_general_importexport($nonce);
|
126 |
|
127 |
/* settings - scanner */
|
128 |
-
$params['Settings.Scanner.
|
129 |
$params['Settings.Scanner.IntegrityDiffUtility'] = SucuriScanSettingsIntegrity::diffUtility($nonce);
|
130 |
$params['Settings.Scanner.IntegrityLanguage'] = SucuriScanSettingsIntegrity::language($nonce);
|
131 |
$params['Settings.Scanner.IntegrityCache'] = SucuriScanSettingsIntegrity::cache($nonce);
|
@@ -163,7 +161,6 @@ function sucuriscan_settings_page()
|
|
163 |
/* settings - api service */
|
164 |
$params['Settings.APIService.Status'] = sucuriscan_settings_apiservice_status($nonce);
|
165 |
$params['Settings.APIService.Proxy'] = sucuriscan_settings_apiservice_proxy();
|
166 |
-
$params['Settings.APIService.Timeout'] = sucuriscan_settings_apiservice_timeout($nonce);
|
167 |
|
168 |
/* settings - website info */
|
169 |
$params['Settings.Webinfo.Details'] = sucuriscan_settings_webinfo_details();
|
@@ -183,7 +180,7 @@ function sucuriscan_ajax()
|
|
183 |
if (SucuriScanInterface::checkNonce()) {
|
184 |
SucuriScanAuditLogs::ajaxAuditLogs();
|
185 |
SucuriScanAuditLogs::ajaxAuditLogsReport();
|
186 |
-
SucuriScanAuditLogs::
|
187 |
SucuriScanSiteCheck::ajaxMalwareScan();
|
188 |
SucuriScanFirewall::auditlogsAjax();
|
189 |
SucuriScanIntegrity::ajaxIntegrity();
|
117 |
$params['Settings.General.ApiKey'] = sucuriscan_settings_general_apikey($nonce);
|
118 |
$params['Settings.General.DataStorage'] = sucuriscan_settings_general_datastorage();
|
119 |
$params['Settings.General.SelfHosting'] = sucuriscan_settings_general_selfhosting($nonce);
|
|
|
120 |
$params['Settings.General.ReverseProxy'] = sucuriscan_settings_general_reverseproxy($nonce);
|
121 |
$params['Settings.General.IPDiscoverer'] = sucuriscan_settings_general_ipdiscoverer($nonce);
|
|
|
122 |
$params['Settings.General.AuditLogStats'] = sucuriscan_settings_general_auditlogstats($nonce);
|
123 |
$params['Settings.General.ImportExport'] = sucuriscan_settings_general_importexport($nonce);
|
124 |
|
125 |
/* settings - scanner */
|
126 |
+
$params['Settings.Scanner.Cronjobs'] = SucuriScanSettingsScanner::cronjobs();
|
127 |
$params['Settings.Scanner.IntegrityDiffUtility'] = SucuriScanSettingsIntegrity::diffUtility($nonce);
|
128 |
$params['Settings.Scanner.IntegrityLanguage'] = SucuriScanSettingsIntegrity::language($nonce);
|
129 |
$params['Settings.Scanner.IntegrityCache'] = SucuriScanSettingsIntegrity::cache($nonce);
|
161 |
/* settings - api service */
|
162 |
$params['Settings.APIService.Status'] = sucuriscan_settings_apiservice_status($nonce);
|
163 |
$params['Settings.APIService.Proxy'] = sucuriscan_settings_apiservice_proxy();
|
|
|
164 |
|
165 |
/* settings - website info */
|
166 |
$params['Settings.Webinfo.Details'] = sucuriscan_settings_webinfo_details();
|
180 |
if (SucuriScanInterface::checkNonce()) {
|
181 |
SucuriScanAuditLogs::ajaxAuditLogs();
|
182 |
SucuriScanAuditLogs::ajaxAuditLogsReport();
|
183 |
+
SucuriScanAuditLogs::ajaxAuditLogsSendLogs();
|
184 |
SucuriScanSiteCheck::ajaxMalwareScan();
|
185 |
SucuriScanFirewall::auditlogsAjax();
|
186 |
SucuriScanIntegrity::ajaxIntegrity();
|
src/settings-apiservice.php
CHANGED
@@ -61,40 +61,6 @@ function sucuriscan_settings_apiservice_status($nonce)
|
|
61 |
return SucuriScanTemplate::getSection('settings-apiservice-status', $params);
|
62 |
}
|
63 |
|
64 |
-
/**
|
65 |
-
* Returns the HTML to configure the API service timeout.
|
66 |
-
*
|
67 |
-
* @param bool $nonce True if the CSRF protection worked, false otherwise.
|
68 |
-
* @return string HTML for the API service timeout option.
|
69 |
-
*/
|
70 |
-
function sucuriscan_settings_apiservice_timeout($nonce)
|
71 |
-
{
|
72 |
-
$params = array();
|
73 |
-
|
74 |
-
// Update the API request timeout.
|
75 |
-
if ($nonce) {
|
76 |
-
$timeout = (int) SucuriScanRequest::post(':request_timeout', '[0-9]+');
|
77 |
-
|
78 |
-
if ($timeout > 0) {
|
79 |
-
if ($timeout <= SUCURISCAN_MAX_REQUEST_TIMEOUT) {
|
80 |
-
$message = 'API request timeout set to <code>' . $timeout . '</code> seconds.';
|
81 |
-
|
82 |
-
SucuriScanOption::updateOption(':request_timeout', $timeout);
|
83 |
-
SucuriScanEvent::reportInfoEvent($message);
|
84 |
-
SucuriScanEvent::notifyEvent('plugin_change', $message);
|
85 |
-
SucuriScanInterface::info(__('HTTPTimeoutChange', SUCURISCAN_TEXTDOMAIN));
|
86 |
-
} else {
|
87 |
-
SucuriScanInterface::error(__('HTTPTimeoutFailure', SUCURISCAN_TEXTDOMAIN));
|
88 |
-
}
|
89 |
-
}
|
90 |
-
}
|
91 |
-
|
92 |
-
$params['MaxRequestTimeout'] = SUCURISCAN_MAX_REQUEST_TIMEOUT;
|
93 |
-
$params['RequestTimeout'] = SucuriScanOption::getOption(':request_timeout') . ' seconds';
|
94 |
-
|
95 |
-
return SucuriScanTemplate::getSection('settings-apiservice-timeout', $params);
|
96 |
-
}
|
97 |
-
|
98 |
/**
|
99 |
* Returns the HTML to configure the API service proxy.
|
100 |
*
|
61 |
return SucuriScanTemplate::getSection('settings-apiservice-status', $params);
|
62 |
}
|
63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
/**
|
65 |
* Returns the HTML to configure the API service proxy.
|
66 |
*
|
src/settings-general.php
CHANGED
@@ -83,7 +83,7 @@ function sucuriscan_settings_general_apikey($nonce)
|
|
83 |
// Save API key after it was recovered by the administrator.
|
84 |
if ($api_key = SucuriScanRequest::post(':manual_api_key')) {
|
85 |
SucuriScanAPI::setPluginKey($api_key, true);
|
86 |
-
SucuriScanEvent::
|
87 |
SucuriScanEvent::reportInfoEvent('Sucuri API key was added manually.');
|
88 |
}
|
89 |
|
@@ -338,124 +338,6 @@ function sucuriscan_settings_general_selfhosting($nonce)
|
|
338 |
return SucuriScanTemplate::getSection('settings-general-selfhosting', $params);
|
339 |
}
|
340 |
|
341 |
-
/**
|
342 |
-
* Renders a page with information about the cronjobs feature.
|
343 |
-
*
|
344 |
-
* @param bool $nonce True if the CSRF protection worked.
|
345 |
-
* @return string Page with information about the cronjobs.
|
346 |
-
*/
|
347 |
-
function sucuriscan_settings_general_cronjobs()
|
348 |
-
{
|
349 |
-
$params = array(
|
350 |
-
'Cronjobs.List' => '',
|
351 |
-
'Cronjobs.Total' => 0,
|
352 |
-
'Cronjob.Schedules' => '',
|
353 |
-
);
|
354 |
-
|
355 |
-
$schedule_allowed = SucuriScanEvent::availableSchedules();
|
356 |
-
|
357 |
-
if (SucuriScanInterface::checkNonce()) {
|
358 |
-
// Modify the scheduled tasks (run now, remove, re-schedule).
|
359 |
-
$available = ($schedule_allowed === null)
|
360 |
-
? SucuriScanEvent::availableSchedules()
|
361 |
-
: $schedule_allowed;
|
362 |
-
$allowed_actions = array_keys($available);
|
363 |
-
$allowed_actions[] = 'runnow';
|
364 |
-
$allowed_actions[] = 'remove';
|
365 |
-
$allowed_actions = sprintf('(%s)', implode('|', $allowed_actions));
|
366 |
-
|
367 |
-
if ($cronjob_action = SucuriScanRequest::post(':cronjob_action', $allowed_actions)) {
|
368 |
-
$cronjobs = SucuriScanRequest::post(':cronjobs', '_array');
|
369 |
-
|
370 |
-
if (!empty($cronjobs)) {
|
371 |
-
$total_tasks = count($cronjobs);
|
372 |
-
|
373 |
-
if ($cronjob_action == 'runnow') {
|
374 |
-
/* Force execution of the selected scheduled tasks. */
|
375 |
-
SucuriScanInterface::info(sprintf(
|
376 |
-
__('CronjobsWillRunSoon', SUCURISCAN_TEXTDOMAIN),
|
377 |
-
$total_tasks /* some cronjobs will be ignored */
|
378 |
-
));
|
379 |
-
SucuriScanEvent::reportNoticeEvent(sprintf(
|
380 |
-
'Force execution of scheduled tasks: (multiple entries): %s',
|
381 |
-
@implode(',', $cronjobs)
|
382 |
-
));
|
383 |
-
|
384 |
-
foreach ($cronjobs as $task_name) {
|
385 |
-
wp_schedule_single_event(time() + 10, $task_name);
|
386 |
-
}
|
387 |
-
} elseif ($cronjob_action == 'remove' || $cronjob_action == '_oneoff') {
|
388 |
-
/* Force deletion of the selected scheduled tasks. */
|
389 |
-
SucuriScanInterface::info(sprintf(
|
390 |
-
__('CronjobsWereDeleted', SUCURISCAN_TEXTDOMAIN),
|
391 |
-
$total_tasks /* some cronjobs will be ignored */
|
392 |
-
));
|
393 |
-
SucuriScanEvent::reportNoticeEvent(sprintf(
|
394 |
-
'Delete scheduled tasks: (multiple entries): %s',
|
395 |
-
@implode(',', $cronjobs)
|
396 |
-
));
|
397 |
-
|
398 |
-
foreach ($cronjobs as $task_name) {
|
399 |
-
wp_clear_scheduled_hook($task_name);
|
400 |
-
}
|
401 |
-
} else {
|
402 |
-
SucuriScanInterface::info(sprintf(
|
403 |
-
__('CronjobsWereReinstalled', SUCURISCAN_TEXTDOMAIN),
|
404 |
-
$total_tasks, /* some cronjobs will be ignored */
|
405 |
-
$cronjob_action /* frequency to run cronjob */
|
406 |
-
));
|
407 |
-
SucuriScanEvent::reportNoticeEvent(sprintf(
|
408 |
-
'Re-configure scheduled tasks %s: (multiple entries): %s',
|
409 |
-
$cronjob_action,
|
410 |
-
@implode(',', $cronjobs)
|
411 |
-
));
|
412 |
-
|
413 |
-
foreach ($cronjobs as $task_name) {
|
414 |
-
$next_due = wp_next_scheduled($task_name);
|
415 |
-
wp_schedule_event($next_due, $cronjob_action, $task_name);
|
416 |
-
}
|
417 |
-
}
|
418 |
-
} else {
|
419 |
-
SucuriScanInterface::error(__('CronjobsWereNotSelected', SUCURISCAN_TEXTDOMAIN));
|
420 |
-
}
|
421 |
-
}
|
422 |
-
}
|
423 |
-
|
424 |
-
$cronjobs = _get_cron_array();
|
425 |
-
$available = ($schedule_allowed === null)
|
426 |
-
? SucuriScanEvent::availableSchedules()
|
427 |
-
: $schedule_allowed;
|
428 |
-
|
429 |
-
/* Hardcode the first one to allow the immediate execution of the cronjob(s) */
|
430 |
-
$params['Cronjob.Schedules'] .= '<option value="runnow">'
|
431 |
-
. __('CronjobRunNow', SUCURISCAN_TEXTDOMAIN) . '</option>';
|
432 |
-
|
433 |
-
foreach ($available as $freq => $name) {
|
434 |
-
$params['Cronjob.Schedules'] .= sprintf('<option value="%s">%s</option>', $freq, $name);
|
435 |
-
}
|
436 |
-
|
437 |
-
foreach ($cronjobs as $timestamp => $cronhooks) {
|
438 |
-
foreach ((array) $cronhooks as $hook => $events) {
|
439 |
-
foreach ((array) $events as $key => $event) {
|
440 |
-
if (empty($event['args'])) {
|
441 |
-
$event['args'] = array('[]');
|
442 |
-
}
|
443 |
-
|
444 |
-
$params['Cronjobs.Total'] += 1;
|
445 |
-
$params['Cronjobs.List'] .=
|
446 |
-
SucuriScanTemplate::getSnippet('settings-general-cronjobs', array(
|
447 |
-
'Cronjob.Hook' => $hook,
|
448 |
-
'Cronjob.Schedule' => $event['schedule'],
|
449 |
-
'Cronjob.NextTime' => SucuriScan::datetime($timestamp),
|
450 |
-
'Cronjob.Arguments' => SucuriScan::implode(', ', $event['args']),
|
451 |
-
));
|
452 |
-
}
|
453 |
-
}
|
454 |
-
}
|
455 |
-
|
456 |
-
return SucuriScanTemplate::getSection('settings-general-cronjobs', $params);
|
457 |
-
}
|
458 |
-
|
459 |
/**
|
460 |
* Renders a page with information about the reverse proxy feature.
|
461 |
*
|
@@ -576,44 +458,6 @@ function sucuriscan_settings_general_ipdiscoverer($nonce)
|
|
576 |
return SucuriScanTemplate::getSection('settings-general-ipdiscoverer', $params);
|
577 |
}
|
578 |
|
579 |
-
/**
|
580 |
-
* Renders a page with information about the comment monitor feature.
|
581 |
-
*
|
582 |
-
* @param bool $nonce True if the CSRF protection worked.
|
583 |
-
* @return string Page with information about the comment monitor.
|
584 |
-
*/
|
585 |
-
function sucuriscan_settings_general_commentmonitor($nonce)
|
586 |
-
{
|
587 |
-
$params = array(
|
588 |
-
'CommentMonitorStatus' => __('Enabled', SUCURISCAN_TEXTDOMAIN),
|
589 |
-
'CommentMonitorSwitchText' => __('Disable', SUCURISCAN_TEXTDOMAIN),
|
590 |
-
'CommentMonitorSwitchValue' => 'disable',
|
591 |
-
);
|
592 |
-
|
593 |
-
// Configure the comment monitor option.
|
594 |
-
if ($nonce) {
|
595 |
-
$monitor = SucuriScanRequest::post(':comment_monitor', '(en|dis)able');
|
596 |
-
|
597 |
-
if ($monitor) {
|
598 |
-
$action_d = $monitor . 'd';
|
599 |
-
$message = 'Comment monitor was <code>' . $action_d . '</code>';
|
600 |
-
|
601 |
-
SucuriScanOption::updateOption(':comment_monitor', $action_d);
|
602 |
-
SucuriScanEvent::reportInfoEvent($message);
|
603 |
-
SucuriScanEvent::notifyEvent('plugin_change', $message);
|
604 |
-
SucuriScanInterface::info(__('CommentMonitorStatus', SUCURISCAN_TEXTDOMAIN));
|
605 |
-
}
|
606 |
-
}
|
607 |
-
|
608 |
-
if (SucuriScanOption::isDisabled(':comment_monitor')) {
|
609 |
-
$params['CommentMonitorStatus'] = __('Disabled', SUCURISCAN_TEXTDOMAIN);
|
610 |
-
$params['CommentMonitorSwitchText'] = __('Enable', SUCURISCAN_TEXTDOMAIN);
|
611 |
-
$params['CommentMonitorSwitchValue'] = 'enable';
|
612 |
-
}
|
613 |
-
|
614 |
-
return SucuriScanTemplate::getSection('settings-general-commentmonitor', $params);
|
615 |
-
}
|
616 |
-
|
617 |
/**
|
618 |
* Renders a page with information about the auditlog stats feature.
|
619 |
*
|
@@ -658,7 +502,6 @@ function sucuriscan_settings_general_importexport($nonce)
|
|
658 |
':api_protocol',
|
659 |
':api_service',
|
660 |
':cloudproxy_apikey',
|
661 |
-
':comment_monitor',
|
662 |
':diff_utility',
|
663 |
':dns_lookups',
|
664 |
':email_subject',
|
@@ -692,9 +535,7 @@ function sucuriscan_settings_general_importexport($nonce)
|
|
692 |
':notify_widget_added',
|
693 |
':notify_widget_deleted',
|
694 |
':prettify_mails',
|
695 |
-
':request_timeout',
|
696 |
':revproxy',
|
697 |
-
':scan_frequency',
|
698 |
':selfhosting_fpath',
|
699 |
':selfhosting_monitor',
|
700 |
':use_wpmail',
|
83 |
// Save API key after it was recovered by the administrator.
|
84 |
if ($api_key = SucuriScanRequest::post(':manual_api_key')) {
|
85 |
SucuriScanAPI::setPluginKey($api_key, true);
|
86 |
+
SucuriScanEvent::installScheduledTask();
|
87 |
SucuriScanEvent::reportInfoEvent('Sucuri API key was added manually.');
|
88 |
}
|
89 |
|
338 |
return SucuriScanTemplate::getSection('settings-general-selfhosting', $params);
|
339 |
}
|
340 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
341 |
/**
|
342 |
* Renders a page with information about the reverse proxy feature.
|
343 |
*
|
458 |
return SucuriScanTemplate::getSection('settings-general-ipdiscoverer', $params);
|
459 |
}
|
460 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
461 |
/**
|
462 |
* Renders a page with information about the auditlog stats feature.
|
463 |
*
|
502 |
':api_protocol',
|
503 |
':api_service',
|
504 |
':cloudproxy_apikey',
|
|
|
505 |
':diff_utility',
|
506 |
':dns_lookups',
|
507 |
':email_subject',
|
535 |
':notify_widget_added',
|
536 |
':notify_widget_deleted',
|
537 |
':prettify_mails',
|
|
|
538 |
':revproxy',
|
|
|
539 |
':selfhosting_fpath',
|
540 |
':selfhosting_monitor',
|
541 |
':use_wpmail',
|
src/settings-scanner.php
CHANGED
@@ -22,61 +22,125 @@ if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) {
|
|
22 |
class SucuriScanSettingsScanner extends SucuriScanSettings
|
23 |
{
|
24 |
/**
|
25 |
-
*
|
26 |
*
|
27 |
-
*
|
28 |
-
*
|
29 |
-
* includes the frequency in which such scanner will run and information about
|
30 |
-
* the availability of the required dependencies.
|
31 |
-
*
|
32 |
-
* @return string HTML for the project scanner options.
|
33 |
*/
|
34 |
-
public static function
|
35 |
{
|
36 |
-
$params = array(
|
|
|
|
|
|
|
|
|
37 |
|
38 |
$schedule_allowed = SucuriScanEvent::availableSchedules();
|
39 |
|
40 |
if (SucuriScanInterface::checkNonce()) {
|
41 |
-
// Modify the
|
42 |
-
|
43 |
-
|
44 |
-
|
|
|
|
|
|
|
|
|
45 |
|
46 |
-
|
47 |
-
|
48 |
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
-
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
-
|
58 |
-
|
59 |
-
|
|
|
|
|
|
|
|
|
60 |
}
|
61 |
}
|
62 |
}
|
63 |
|
64 |
-
$
|
|
|
|
|
|
|
65 |
|
66 |
-
|
67 |
-
$
|
|
|
68 |
|
69 |
-
$
|
70 |
-
|
|
|
71 |
|
72 |
-
$
|
73 |
-
|
|
|
|
|
|
|
|
|
74 |
|
75 |
-
|
76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
}
|
78 |
|
79 |
-
|
|
|
|
|
|
|
80 |
}
|
81 |
|
82 |
/**
|
22 |
class SucuriScanSettingsScanner extends SucuriScanSettings
|
23 |
{
|
24 |
/**
|
25 |
+
* Renders a page with information about the cronjobs feature.
|
26 |
*
|
27 |
+
* @param bool $nonce True if the CSRF protection worked.
|
28 |
+
* @return string Page with information about the cronjobs.
|
|
|
|
|
|
|
|
|
29 |
*/
|
30 |
+
public static function cronjobs()
|
31 |
{
|
32 |
+
$params = array(
|
33 |
+
'Cronjobs.List' => '',
|
34 |
+
'Cronjobs.Total' => 0,
|
35 |
+
'Cronjob.Schedules' => '',
|
36 |
+
);
|
37 |
|
38 |
$schedule_allowed = SucuriScanEvent::availableSchedules();
|
39 |
|
40 |
if (SucuriScanInterface::checkNonce()) {
|
41 |
+
// Modify the scheduled tasks (run now, remove, re-schedule).
|
42 |
+
$available = ($schedule_allowed === null)
|
43 |
+
? SucuriScanEvent::availableSchedules()
|
44 |
+
: $schedule_allowed;
|
45 |
+
$allowed_actions = array_keys($available);
|
46 |
+
$allowed_actions[] = 'runnow'; /* execute in the next 10 seconds */
|
47 |
+
$allowed_actions[] = 'remove'; /* can be reinstalled automatically */
|
48 |
+
$allowed_actions = sprintf('(%s)', implode('|', $allowed_actions));
|
49 |
|
50 |
+
if ($cronjob_action = SucuriScanRequest::post(':cronjob_action', $allowed_actions)) {
|
51 |
+
$cronjobs = SucuriScanRequest::post(':cronjobs', '_array');
|
52 |
|
53 |
+
if (!empty($cronjobs)) {
|
54 |
+
$total_tasks = count($cronjobs);
|
55 |
+
|
56 |
+
if ($cronjob_action == 'runnow') {
|
57 |
+
/* Force execution of the selected scheduled tasks. */
|
58 |
+
SucuriScanInterface::info(sprintf(
|
59 |
+
__('CronjobsWillRunSoon', SUCURISCAN_TEXTDOMAIN),
|
60 |
+
$total_tasks /* some cronjobs will be ignored */
|
61 |
+
));
|
62 |
+
SucuriScanEvent::reportNoticeEvent(sprintf(
|
63 |
+
'Force execution of scheduled tasks: (multiple entries): %s',
|
64 |
+
@implode(',', $cronjobs)
|
65 |
+
));
|
66 |
+
|
67 |
+
foreach ($cronjobs as $task_name) {
|
68 |
+
wp_schedule_single_event(time() + 10, $task_name);
|
69 |
+
}
|
70 |
+
} elseif ($cronjob_action == 'remove' || $cronjob_action == '_oneoff') {
|
71 |
+
/* Force deletion of the selected scheduled tasks. */
|
72 |
+
SucuriScanInterface::info(sprintf(
|
73 |
+
__('CronjobsWereDeleted', SUCURISCAN_TEXTDOMAIN),
|
74 |
+
$total_tasks /* some cronjobs will be ignored */
|
75 |
+
));
|
76 |
+
SucuriScanEvent::reportNoticeEvent(sprintf(
|
77 |
+
'Delete scheduled tasks: (multiple entries): %s',
|
78 |
+
@implode(',', $cronjobs)
|
79 |
+
));
|
80 |
|
81 |
+
foreach ($cronjobs as $task_name) {
|
82 |
+
wp_clear_scheduled_hook($task_name);
|
83 |
+
}
|
84 |
+
} else {
|
85 |
+
SucuriScanInterface::info(sprintf(
|
86 |
+
__('CronjobsWereReinstalled', SUCURISCAN_TEXTDOMAIN),
|
87 |
+
$total_tasks, /* some cronjobs will be ignored */
|
88 |
+
$cronjob_action /* frequency to run cronjob */
|
89 |
+
));
|
90 |
+
SucuriScanEvent::reportNoticeEvent(sprintf(
|
91 |
+
'Re-configure scheduled tasks %s: (multiple entries): %s',
|
92 |
+
$cronjob_action,
|
93 |
+
@implode(',', $cronjobs)
|
94 |
+
));
|
95 |
|
96 |
+
foreach ($cronjobs as $task_name) {
|
97 |
+
$next_due = wp_next_scheduled($task_name);
|
98 |
+
wp_schedule_event($next_due, $cronjob_action, $task_name);
|
99 |
+
}
|
100 |
+
}
|
101 |
+
} else {
|
102 |
+
SucuriScanInterface::error(__('CronjobsWereNotSelected', SUCURISCAN_TEXTDOMAIN));
|
103 |
}
|
104 |
}
|
105 |
}
|
106 |
|
107 |
+
$cronjobs = _get_cron_array();
|
108 |
+
$available = ($schedule_allowed === null)
|
109 |
+
? SucuriScanEvent::availableSchedules()
|
110 |
+
: $schedule_allowed;
|
111 |
|
112 |
+
/* Hardcode the first one to allow the immediate execution of the cronjob(s) */
|
113 |
+
$params['Cronjob.Schedules'] .= '<option value="runnow">'
|
114 |
+
. __('CronjobRunNow', SUCURISCAN_TEXTDOMAIN) . '</option>';
|
115 |
|
116 |
+
foreach ($available as $freq => $name) {
|
117 |
+
$params['Cronjob.Schedules'] .= sprintf('<option value="%s">%s</option>', $freq, $name);
|
118 |
+
}
|
119 |
|
120 |
+
foreach ($cronjobs as $timestamp => $cronhooks) {
|
121 |
+
foreach ((array) $cronhooks as $hook => $events) {
|
122 |
+
foreach ((array) $events as $key => $event) {
|
123 |
+
if (empty($event['args'])) {
|
124 |
+
$event['args'] = array('[]');
|
125 |
+
}
|
126 |
|
127 |
+
$params['Cronjobs.Total'] += 1;
|
128 |
+
$params['Cronjobs.List'] .=
|
129 |
+
SucuriScanTemplate::getSnippet('settings-scanner-cronjobs', array(
|
130 |
+
'Cronjob.Hook' => $hook,
|
131 |
+
'Cronjob.Schedule' => $event['schedule'],
|
132 |
+
'Cronjob.NextTime' => SucuriScan::datetime($timestamp),
|
133 |
+
'Cronjob.NextTimeHuman' => SucuriScan::humanTime($timestamp),
|
134 |
+
'Cronjob.Arguments' => SucuriScan::implode(', ', $event['args']),
|
135 |
+
));
|
136 |
+
}
|
137 |
+
}
|
138 |
}
|
139 |
|
140 |
+
$hasSPL = SucuriScanFileInfo::isSplAvailable();
|
141 |
+
$params['NoSPL.Visibility'] = SucuriScanTemplate::visibility(!$hasSPL);
|
142 |
+
|
143 |
+
return SucuriScanTemplate::getSection('settings-scanner-cronjobs', $params);
|
144 |
}
|
145 |
|
146 |
/**
|
src/sitecheck.lib.php
CHANGED
@@ -32,8 +32,6 @@ if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) {
|
|
32 |
*/
|
33 |
class SucuriScanSiteCheck extends SucuriScanAPI
|
34 |
{
|
35 |
-
private static $scanRequests;
|
36 |
-
|
37 |
/**
|
38 |
* Executes a malware scan against the specified website.
|
39 |
*
|
@@ -92,32 +90,25 @@ class SucuriScanSiteCheck extends SucuriScanAPI
|
|
92 |
$cache = new SucuriScanCache('sitecheck');
|
93 |
$results = $cache->get('scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array');
|
94 |
|
95 |
-
/* return cached malware scan results. */
|
96 |
-
if ($results && !empty($results)) {
|
97 |
-
return $results;
|
98 |
-
}
|
99 |
-
|
100 |
/**
|
101 |
-
*
|
102 |
*
|
103 |
-
*
|
104 |
-
*
|
105 |
-
*
|
106 |
-
*
|
107 |
-
*
|
108 |
*
|
109 |
-
*
|
110 |
-
*
|
111 |
-
* The second and subsequent scan requests (from the other methods) are
|
112 |
-
* expected to return the data from the cache, hence the position of the
|
113 |
-
* conditional in this specific line, right after the cache lifetime is
|
114 |
-
* checked. If the cache is invalid (because the first scan failed) or
|
115 |
-
* if the cache has expired (and the new request fails) we will assume
|
116 |
-
* that the other requests (around ten or so) will fail too.
|
117 |
*/
|
118 |
-
|
119 |
-
|
120 |
-
|
|
|
|
|
|
|
|
|
|
|
121 |
}
|
122 |
|
123 |
/* send HTTP request to SiteCheck's API service. */
|
@@ -545,19 +536,17 @@ class SucuriScanSiteCheck extends SucuriScanAPI
|
|
545 |
* with a missing line in the coverage. Since the test case takes care of
|
546 |
* the functionality of this code we will assume that it is fully covered.
|
547 |
*/
|
548 |
-
function ajaxMalwareScan()
|
549 |
{
|
550 |
if (SucuriScanRequest::post('form_action') !== 'malware_scan') {
|
551 |
return;
|
552 |
}
|
553 |
|
554 |
-
$response = array();
|
555 |
-
|
556 |
ob_start();
|
557 |
-
$result = SucuriScanSiteCheck::malware();
|
558 |
-
$errors = ob_get_clean(); /* capture possible errors */
|
559 |
-
$response['malware'] = empty($errors) ? $result : '';
|
560 |
|
|
|
|
|
|
|
561 |
$response['blacklist'] = SucuriScanSiteCheck::blacklist();
|
562 |
$response['recommendations'] = SucuriScanSiteCheck::recommendations();
|
563 |
|
@@ -574,6 +563,14 @@ class SucuriScanSiteCheck extends SucuriScanAPI
|
|
574 |
'content' => SucuriScanSiteCheck::scriptsContent(),
|
575 |
);
|
576 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
577 |
wp_send_json($response, 200);
|
578 |
}
|
579 |
}
|
32 |
*/
|
33 |
class SucuriScanSiteCheck extends SucuriScanAPI
|
34 |
{
|
|
|
|
|
35 |
/**
|
36 |
* Executes a malware scan against the specified website.
|
37 |
*
|
90 |
$cache = new SucuriScanCache('sitecheck');
|
91 |
$results = $cache->get('scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array');
|
92 |
|
|
|
|
|
|
|
|
|
|
|
93 |
/**
|
94 |
+
* Allow the user to scan foreign domains.
|
95 |
*
|
96 |
+
* This condition allows for the execution of the malware scanner on a
|
97 |
+
* website different than the one where the plugin is installed. This is
|
98 |
+
* basically the same as scanning any domain on the SiteCheck website.
|
99 |
+
* In this case, this is mostly used to allow the development execute
|
100 |
+
* tests and to troubleshoot issues reported by other users.
|
101 |
*
|
102 |
+
* @var boolean
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
*/
|
104 |
+
if ($custom = SucuriScanRequest::get('s')) {
|
105 |
+
$tld = SucuriScan::escape($custom);
|
106 |
+
$results = false /* invalid cache */;
|
107 |
+
}
|
108 |
+
|
109 |
+
/* return cached malware scan results. */
|
110 |
+
if ($results && !empty($results)) {
|
111 |
+
return $results;
|
112 |
}
|
113 |
|
114 |
/* send HTTP request to SiteCheck's API service. */
|
536 |
* with a missing line in the coverage. Since the test case takes care of
|
537 |
* the functionality of this code we will assume that it is fully covered.
|
538 |
*/
|
539 |
+
public static function ajaxMalwareScan()
|
540 |
{
|
541 |
if (SucuriScanRequest::post('form_action') !== 'malware_scan') {
|
542 |
return;
|
543 |
}
|
544 |
|
|
|
|
|
545 |
ob_start();
|
|
|
|
|
|
|
546 |
|
547 |
+
$response = array();
|
548 |
+
|
549 |
+
$response['malware'] = SucuriScanSiteCheck::malware();
|
550 |
$response['blacklist'] = SucuriScanSiteCheck::blacklist();
|
551 |
$response['recommendations'] = SucuriScanSiteCheck::recommendations();
|
552 |
|
563 |
'content' => SucuriScanSiteCheck::scriptsContent(),
|
564 |
);
|
565 |
|
566 |
+
$errors = ob_get_clean(); /* capture possible errors */
|
567 |
+
|
568 |
+
if (!empty($errors)) {
|
569 |
+
$response['malware'] = '';
|
570 |
+
$response['blacklist'] = '';
|
571 |
+
$response['recommendations'] = '';
|
572 |
+
}
|
573 |
+
|
574 |
wp_send_json($response, 200);
|
575 |
}
|
576 |
}
|
src/sucuriscan.lib.php
CHANGED
@@ -152,6 +152,61 @@ class SucuriScan
|
|
152 |
return $result;
|
153 |
}
|
154 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
/**
|
156 |
* Check if the admin init hook must not be intercepted.
|
157 |
*
|
@@ -338,6 +393,7 @@ class SucuriScan
|
|
338 |
SucuriScanEvent::reportSiteVersion();
|
339 |
SucuriScanIntegrity::getIntegrityStatus(true);
|
340 |
SucuriScanSettingsPosthack::availableUpdatesContent(true);
|
|
|
341 |
}
|
342 |
|
343 |
/**
|
152 |
return $result;
|
153 |
}
|
154 |
|
155 |
+
/**
|
156 |
+
* Returns the human version of the time difference.
|
157 |
+
*
|
158 |
+
* If the timestamp is in the past in comparison with the current time, it
|
159 |
+
* will return a string in the form of "X time ago". If the timestamp is in
|
160 |
+
* the future in comparison with the current time, it will return a string
|
161 |
+
* in the form of "in X time". If the timestamp is the same as the current
|
162 |
+
* time it will return "right now".
|
163 |
+
*
|
164 |
+
* @param integer $time Unix timestamp.
|
165 |
+
* @return string Different between timestamp and current time.
|
166 |
+
*/
|
167 |
+
public static function humanTime($time = 0)
|
168 |
+
{
|
169 |
+
$now = time();
|
170 |
+
|
171 |
+
if ($time === $now) {
|
172 |
+
return 'right now';
|
173 |
+
}
|
174 |
+
|
175 |
+
$result = '';
|
176 |
+
$template = '';
|
177 |
+
$diff = $now - $time;
|
178 |
+
$groups = array(
|
179 |
+
31536000 => 'year',
|
180 |
+
2592000 => 'month',
|
181 |
+
86400 => 'day',
|
182 |
+
3600 => 'hour',
|
183 |
+
60 => 'minute',
|
184 |
+
1 => 'second',
|
185 |
+
);
|
186 |
+
|
187 |
+
if ($time < $now) {
|
188 |
+
$template = '%d %s ago';
|
189 |
+
} else {
|
190 |
+
$template = 'in %d %s';
|
191 |
+
}
|
192 |
+
|
193 |
+
foreach ($groups as $secs => $label) {
|
194 |
+
$distance = abs($diff / $secs);
|
195 |
+
|
196 |
+
if ($distance >= 1) {
|
197 |
+
$plural = (round($distance) == 1) ? '' : 's';
|
198 |
+
$result = sprintf(
|
199 |
+
$template,
|
200 |
+
round($distance),
|
201 |
+
$label . $plural
|
202 |
+
);
|
203 |
+
break;
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
return $result;
|
208 |
+
}
|
209 |
+
|
210 |
/**
|
211 |
* Check if the admin init hook must not be intercepted.
|
212 |
*
|
393 |
SucuriScanEvent::reportSiteVersion();
|
394 |
SucuriScanIntegrity::getIntegrityStatus(true);
|
395 |
SucuriScanSettingsPosthack::availableUpdatesContent(true);
|
396 |
+
SucuriScanEvent::sendLogsFromQueue(); /* blocking; keep at the end */
|
397 |
}
|
398 |
|
399 |
/**
|
sucuri.php
CHANGED
@@ -7,7 +7,7 @@
|
|
7 |
* Author URI: https://sucuri.net/
|
8 |
* Text Domain: sucuri-scanner
|
9 |
* Author: Sucuri Inc.
|
10 |
-
* Version: 1.8.
|
11 |
*/
|
12 |
|
13 |
|
@@ -83,7 +83,7 @@ define('SUCURISCAN', 'sucuriscan');
|
|
83 |
/**
|
84 |
* Current version of the plugin's code.
|
85 |
*/
|
86 |
-
define('SUCURISCAN_VERSION', '1.8.
|
87 |
|
88 |
/**
|
89 |
* The name of the Sucuri plugin main file.
|
@@ -166,7 +166,7 @@ define('SUCURISCAN_AUDITLOGS_PER_PAGE', 50);
|
|
166 |
/**
|
167 |
* The maximum quantity of buttons in the paginations.
|
168 |
*/
|
169 |
-
define('SUCURISCAN_MAX_PAGINATION_BUTTONS',
|
170 |
|
171 |
/**
|
172 |
* Frequency of the file system scans in seconds.
|
@@ -186,7 +186,7 @@ define('SUCURISCAN_GET_PLUGINS_LIFETIME', 1800);
|
|
186 |
/**
|
187 |
* The maximum execution time of a HTTP request before timeout.
|
188 |
*/
|
189 |
-
define('SUCURISCAN_MAX_REQUEST_TIMEOUT',
|
190 |
|
191 |
/**
|
192 |
* Sets the text that will preceed the admin notices.
|
7 |
* Author URI: https://sucuri.net/
|
8 |
* Text Domain: sucuri-scanner
|
9 |
* Author: Sucuri Inc.
|
10 |
+
* Version: 1.8.7
|
11 |
*/
|
12 |
|
13 |
|
83 |
/**
|
84 |
* Current version of the plugin's code.
|
85 |
*/
|
86 |
+
define('SUCURISCAN_VERSION', '1.8.7');
|
87 |
|
88 |
/**
|
89 |
* The name of the Sucuri plugin main file.
|
166 |
/**
|
167 |
* The maximum quantity of buttons in the paginations.
|
168 |
*/
|
169 |
+
define('SUCURISCAN_MAX_PAGINATION_BUTTONS', 16);
|
170 |
|
171 |
/**
|
172 |
* Frequency of the file system scans in seconds.
|
186 |
/**
|
187 |
* The maximum execution time of a HTTP request before timeout.
|
188 |
*/
|
189 |
+
define('SUCURISCAN_MAX_REQUEST_TIMEOUT', 5);
|
190 |
|
191 |
/**
|
192 |
* Sets the text that will preceed the admin notices.
|