Version Description
- Fixed dates and times in activity log alert emails and other emails to be in site's local timezone.
- Added advanced country blocking options which allow bypass if a special URL is hit.
- Added warning in options page if alert email is not configured under alert checkboxes.
- Modified scan times to be within 60 minute window after scheduled time to prevent stampede at the top of the hour on our scanning server.
- Fixed bug on Godaddy and a few other hosts where viewing list of files not in the repo caused error. This was caused by posix functions not being supported on Godaddy and some other hosts.
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 3.2.7 |
Comparing to | |
See all releases |
Code changes from version 3.2.6 to 3.2.7
- js/admin.js +28 -0
- lib/email_newIssues.php +2 -0
- lib/email_unlockRequest.php +2 -0
- lib/menu_countryBlocking.php +13 -0
- lib/menu_options.php +6 -0
- lib/menu_scan.php +2 -1
- lib/menu_scanSchedule.php +2 -0
- lib/unknownFiles.php +12 -4
- lib/viewFullActivityLog.php +2 -1
- lib/wfLog.php +42 -5
- lib/wfUtils.php +3 -0
- lib/wordfenceClass.php +8 -3
- readme.txt +8 -1
- wordfence.php +2 -2
js/admin.js
CHANGED
@@ -959,10 +959,28 @@ window['wordfenceAdmin'] = {
|
|
959 |
saveCountryBlocking: function(){
|
960 |
var action = jQuery('#wfBlockAction').val();
|
961 |
var redirURL = jQuery('#wfRedirURL').val();
|
|
|
|
|
|
|
|
|
962 |
if(action == 'redir' && (! /^https?:\/\/[^\/]+/i.test(redirURL))){
|
963 |
this.colorbox('400px', "Please enter a URL for redirection", "You have chosen to redirect blocked countries to a specific page. You need to enter a URL in the text box provided that starts with http:// or https://");
|
964 |
return;
|
965 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
966 |
var codesArr = [];
|
967 |
var ownCountryBlocked = false;
|
968 |
var self = this;
|
@@ -984,11 +1002,18 @@ window['wordfenceAdmin'] = {
|
|
984 |
this.confirmSaveCountryBlocking();
|
985 |
}
|
986 |
},
|
|
|
|
|
|
|
|
|
987 |
confirmSaveCountryBlocking: function(){
|
988 |
var action = jQuery('#wfBlockAction').val();
|
989 |
var redirURL = jQuery('#wfRedirURL').val();
|
990 |
var loggedInBlocked = jQuery('#wfLoggedInBlocked').is(':checked') ? '1' : '0';
|
991 |
var loginFormBlocked = jQuery('#wfLoginFormBlocked').is(':checked') ? '1' : '0';
|
|
|
|
|
|
|
992 |
|
993 |
jQuery('.wfAjax24').show();
|
994 |
var self = this;
|
@@ -997,6 +1022,9 @@ window['wordfenceAdmin'] = {
|
|
997 |
redirURL: redirURL,
|
998 |
loggedInBlocked: loggedInBlocked,
|
999 |
loginFormBlocked: loginFormBlocked,
|
|
|
|
|
|
|
1000 |
codes: this.countryCodesToSave
|
1001 |
}, function(res){
|
1002 |
jQuery('.wfAjax24').hide();
|
959 |
saveCountryBlocking: function(){
|
960 |
var action = jQuery('#wfBlockAction').val();
|
961 |
var redirURL = jQuery('#wfRedirURL').val();
|
962 |
+
var bypassRedirURL = jQuery('#wfBypassRedirURL').val();
|
963 |
+
var bypassRedirDest = jQuery('#wfBypassRedirDest').val();
|
964 |
+
var bypassViewURL = jQuery('#wfBypassViewURL').val();
|
965 |
+
|
966 |
if(action == 'redir' && (! /^https?:\/\/[^\/]+/i.test(redirURL))){
|
967 |
this.colorbox('400px', "Please enter a URL for redirection", "You have chosen to redirect blocked countries to a specific page. You need to enter a URL in the text box provided that starts with http:// or https://");
|
968 |
return;
|
969 |
}
|
970 |
+
if( bypassRedirURL || bypassRedirDest ){
|
971 |
+
if(! (bypassRedirURL && bypassRedirDest)){
|
972 |
+
this.colorbox('400px', "Missing data from form", "If you want to set up a URL that will bypass country blocking, you must enter a URL that a visitor can hit and the destination they will be redirected to. You have only entered one of these components. Please enter both.");
|
973 |
+
return;
|
974 |
+
}
|
975 |
+
if(bypassRedirURL == bypassRedirDest){
|
976 |
+
this.colorbox('400px', "URLs are the same", "The URL that a user hits to bypass country blocking and the URL they are redirected to are the same. This would cause a circular redirect. Please fix this.");
|
977 |
+
return;
|
978 |
+
}
|
979 |
+
}
|
980 |
+
if(bypassRedirURL && (! /^(?:\/|http:\/\/)/.test(bypassRedirURL))){ this.invalidCountryURLMsg(bypassRedirURL); return; }
|
981 |
+
if(bypassRedirDest && (! /^(?:\/|http:\/\/)/.test(bypassRedirDest))){ this.invalidCountryURLMsg(bypassRedirDest); return; }
|
982 |
+
if(bypassViewURL && (! /^(?:\/|http:\/\/)/.test(bypassViewURL))){ this.invalidCountryURLMsg(bypassViewURL); return; }
|
983 |
+
|
984 |
var codesArr = [];
|
985 |
var ownCountryBlocked = false;
|
986 |
var self = this;
|
1002 |
this.confirmSaveCountryBlocking();
|
1003 |
}
|
1004 |
},
|
1005 |
+
invalidCountryURLMsg: function(URL){
|
1006 |
+
this.colorbox('400px', "Invalid URL", "URL's that you provide for bypassing country blocking must start with '/' or 'http://' without quotes. The URL that is invalid is: " + URL);
|
1007 |
+
return;
|
1008 |
+
},
|
1009 |
confirmSaveCountryBlocking: function(){
|
1010 |
var action = jQuery('#wfBlockAction').val();
|
1011 |
var redirURL = jQuery('#wfRedirURL').val();
|
1012 |
var loggedInBlocked = jQuery('#wfLoggedInBlocked').is(':checked') ? '1' : '0';
|
1013 |
var loginFormBlocked = jQuery('#wfLoginFormBlocked').is(':checked') ? '1' : '0';
|
1014 |
+
var bypassRedirURL = jQuery('#wfBypassRedirURL').val();
|
1015 |
+
var bypassRedirDest = jQuery('#wfBypassRedirDest').val();
|
1016 |
+
var bypassViewURL = jQuery('#wfBypassViewURL').val();
|
1017 |
|
1018 |
jQuery('.wfAjax24').show();
|
1019 |
var self = this;
|
1022 |
redirURL: redirURL,
|
1023 |
loggedInBlocked: loggedInBlocked,
|
1024 |
loginFormBlocked: loginFormBlocked,
|
1025 |
+
bypassRedirURL: bypassRedirURL,
|
1026 |
+
bypassRedirDest: bypassRedirDest,
|
1027 |
+
bypassViewURL: bypassViewURL,
|
1028 |
codes: this.countryCodesToSave
|
1029 |
}, function(res){
|
1030 |
jQuery('.wfAjax24').hide();
|
lib/email_newIssues.php
CHANGED
@@ -1,5 +1,7 @@
|
|
1 |
Wordfence found the following new issues on "<?php echo get_bloginfo('name', 'raw'); ?>".
|
2 |
|
|
|
|
|
3 |
<?php if($totalCriticalIssues > 0){ ?>
|
4 |
Critical Problems:
|
5 |
|
1 |
Wordfence found the following new issues on "<?php echo get_bloginfo('name', 'raw'); ?>".
|
2 |
|
3 |
+
Alert generated at <?php echo wfUtils::localHumanDate(); ?>
|
4 |
+
|
5 |
<?php if($totalCriticalIssues > 0){ ?>
|
6 |
Critical Problems:
|
7 |
|
lib/email_unlockRequest.php
CHANGED
@@ -1,6 +1,8 @@
|
|
1 |
Either you or someone else at IP address <b><?php echo $IP; ?></b> requesed instructions to<br />
|
2 |
regain access to the website <a href="<?php echo wfUtils::getSiteBaseURL(); ?>"><b><?php echo $siteName; ?></b></a>.<br />
|
3 |
<br />
|
|
|
|
|
4 |
If you did not request these instructions then you can safely ignore them.<br />
|
5 |
These instructions <b>will be valid for 30 minutes</b>
|
6 |
from the time they were sent.
|
1 |
Either you or someone else at IP address <b><?php echo $IP; ?></b> requesed instructions to<br />
|
2 |
regain access to the website <a href="<?php echo wfUtils::getSiteBaseURL(); ?>"><b><?php echo $siteName; ?></b></a>.<br />
|
3 |
<br />
|
4 |
+
Request was generated at: <?php echo wfUtils::localHumanDate(); ?><br />
|
5 |
+
<br />
|
6 |
If you did not request these instructions then you can safely ignore them.<br />
|
7 |
These instructions <b>will be valid for 30 minutes</b>
|
8 |
from the time they were sent.
|
lib/menu_countryBlocking.php
CHANGED
@@ -19,6 +19,19 @@ WFAD.countryMap = <?php echo json_encode($wfBulkCountries); ?>;
|
|
19 |
<tr><th>URL to redirect blocked users to:</th><td><input type="text" id="wfRedirURL" value="<?php if(wfConfig::get('cbl_redirURL')){ echo htmlspecialchars(wfConfig::get('cbl_redirURL')); } ?>" /></td></tr>
|
20 |
<tr><th>Block countries even if they are logged in:</th><td><input type="checkbox" id="wfLoggedInBlocked" value="1" <?php if(wfConfig::get('cbl_loggedInBlocked')){ echo 'checked'; } ?> /></td></tr>
|
21 |
<tr><th>Block access to the login form too:</th><td><input type="checkbox" id="wfLoginFormBlocked" value="1" <?php if(wfConfig::get('cbl_loginFormBlocked')){ echo 'checked'; } ?> /></td></tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
</table>
|
23 |
<h2>Select which countries to block</h2>
|
24 |
<div id="wfBulkBlockingContainer" style="margin-bottom: 10px;">
|
19 |
<tr><th>URL to redirect blocked users to:</th><td><input type="text" id="wfRedirURL" value="<?php if(wfConfig::get('cbl_redirURL')){ echo htmlspecialchars(wfConfig::get('cbl_redirURL')); } ?>" /></td></tr>
|
20 |
<tr><th>Block countries even if they are logged in:</th><td><input type="checkbox" id="wfLoggedInBlocked" value="1" <?php if(wfConfig::get('cbl_loggedInBlocked')){ echo 'checked'; } ?> /></td></tr>
|
21 |
<tr><th>Block access to the login form too:</th><td><input type="checkbox" id="wfLoginFormBlocked" value="1" <?php if(wfConfig::get('cbl_loginFormBlocked')){ echo 'checked'; } ?> /></td></tr>
|
22 |
+
<tr><td colspan="2"><h2>Advanced Country Blocking Options</h2></td></tr>
|
23 |
+
<tr><th colspan="2">
|
24 |
+
If user hits the URL
|
25 |
+
<input type="text" id="wfBypassRedirURL" value="<?php echo htmlspecialchars(wfConfig::get('cbl_cblBypassURL', "")); ?>" size="20" />
|
26 |
+
then redirect that user to
|
27 |
+
<input type="text" id="wfBypassRedirDest" value="<?php echo htmlspecialchars(wfConfig::get('cbl_cblBypassURLRedir', "")); ?>" size="20" /> and set a cookie that will bypass all country blocking.
|
28 |
+
</th></tr>
|
29 |
+
<tr><th colspan="2">
|
30 |
+
If user who is allowed to access the site views the URL
|
31 |
+
<input type="text" id="wfBypassViewURL" value="<?php echo htmlspecialchars(wfConfig::get('cbl_cblBypassURL', "")); ?>" size="20" />
|
32 |
+
then set a cookie that will bypass country blocking in future in case that user hits the site from a blocked country.
|
33 |
+
</th></tr>
|
34 |
+
|
35 |
</table>
|
36 |
<h2>Select which countries to block</h2>
|
37 |
<div id="wfBulkBlockingContainer" style="margin-bottom: 10px;">
|
lib/menu_options.php
CHANGED
@@ -50,6 +50,12 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
50 |
<div id="wfConfigAdvanced">
|
51 |
<table class="wfConfigForm">
|
52 |
<tr><td colspan="2"><h3 class="wfConfigHeading">Alerts</h3></td></tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
<tr><th>Alert on critical problems</th><td><input type="checkbox" id="alertOn_critical" class="wfConfigElem" name="alertOn_critical" value="1" <?php $w->cb('alertOn_critical'); ?>/></td></tr>
|
54 |
<tr><th>Alert on warnings</th><td><input type="checkbox" id="alertOn_warnings" class="wfConfigElem" name="alertOn_warnings" value="1" <?php $w->cb('alertOn_warnings'); ?>/></td></tr>
|
55 |
<tr><th>Alert when an IP address is blocked</th><td><input type="checkbox" id="alertOn_block" class="wfConfigElem" name="alertOn_block" value="1" <?php $w->cb('alertOn_block'); ?>/></td></tr>
|
50 |
<div id="wfConfigAdvanced">
|
51 |
<table class="wfConfigForm">
|
52 |
<tr><td colspan="2"><h3 class="wfConfigHeading">Alerts</h3></td></tr>
|
53 |
+
<?php
|
54 |
+
$emails = wfConfig::getAlertEmails();
|
55 |
+
if(sizeof($emails) < 1){
|
56 |
+
echo "<tr><th colspan=\"2\" style=\"color: #F00;\">You have not configured an email to receive alerts yet. Set this up under \"Basic Options\" above.</th></tr>\n";
|
57 |
+
}
|
58 |
+
?>
|
59 |
<tr><th>Alert on critical problems</th><td><input type="checkbox" id="alertOn_critical" class="wfConfigElem" name="alertOn_critical" value="1" <?php $w->cb('alertOn_critical'); ?>/></td></tr>
|
60 |
<tr><th>Alert on warnings</th><td><input type="checkbox" id="alertOn_warnings" class="wfConfigElem" name="alertOn_warnings" value="1" <?php $w->cb('alertOn_warnings'); ?>/></td></tr>
|
61 |
<tr><th>Alert when an IP address is blocked</th><td><input type="checkbox" id="alertOn_block" class="wfConfigElem" name="alertOn_block" value="1" <?php $w->cb('alertOn_block'); ?>/></td></tr>
|
lib/menu_scan.php
CHANGED
@@ -52,6 +52,7 @@
|
|
52 |
$debugOn = wfConfig::get('debugOn', false);
|
53 |
$newestItem = 0;
|
54 |
$sumEvents = array();
|
|
|
55 |
foreach($events as $e){
|
56 |
if(strpos($e['msg'], 'SUM_') !== 0){
|
57 |
if( $debugOn || $e['level'] < 4){
|
@@ -59,7 +60,7 @@
|
|
59 |
if($debugOn){
|
60 |
$typeClass = ' wf' . $e['type'];
|
61 |
}
|
62 |
-
echo '<div class="wfActivityLine' . $typeClass . '">[' . date('M d H:i:s', $e['ctime']) . '] ' . $e['msg'] . '</div>';
|
63 |
}
|
64 |
}
|
65 |
$newestItem = $e['ctime'];
|
52 |
$debugOn = wfConfig::get('debugOn', false);
|
53 |
$newestItem = 0;
|
54 |
$sumEvents = array();
|
55 |
+
$timeOffset = 3600 * get_option('gmt_offset');
|
56 |
foreach($events as $e){
|
57 |
if(strpos($e['msg'], 'SUM_') !== 0){
|
58 |
if( $debugOn || $e['level'] < 4){
|
60 |
if($debugOn){
|
61 |
$typeClass = ' wf' . $e['type'];
|
62 |
}
|
63 |
+
echo '<div class="wfActivityLine' . $typeClass . '">[' . date('M d H:i:s', $e['ctime'] + $timeOffset) . '] ' . $e['msg'] . '</div>';
|
64 |
}
|
65 |
}
|
66 |
$newestItem = $e['ctime'];
|
lib/menu_scanSchedule.php
CHANGED
@@ -22,6 +22,8 @@
|
|
22 |
You can go to the Settings/General menu to change your timezone.
|
23 |
Use the links provided as shortcuts to select scan times. Try clicking
|
24 |
the links several times to advance the time. You can also manually select scan start times for each day.
|
|
|
|
|
25 |
</p>
|
26 |
<p>
|
27 |
<strong>Scan mode:</strong><select id="schedMode" onchange="WFAD.sched_modeChange();">
|
22 |
You can go to the Settings/General menu to change your timezone.
|
23 |
Use the links provided as shortcuts to select scan times. Try clicking
|
24 |
the links several times to advance the time. You can also manually select scan start times for each day.
|
25 |
+
<br /><br />
|
26 |
+
NOTE: Scans run within 1 hour after scheduled time. E.g. A scan scheduled for 1pm will run between 1pm and 2pm. This prevents a stampede on our scanning server at the top of the hour.
|
27 |
</p>
|
28 |
<p>
|
29 |
<strong>Scan mode:</strong><select id="schedMode" onchange="WFAD.sched_modeChange();">
|
lib/unknownFiles.php
CHANGED
@@ -76,10 +76,18 @@ if($fileList){
|
|
76 |
// http://test3.com/?_wfsf=view&nonce=c1ad72bcbd&file=wp-content%2Fplugins%2Fwordfence%2Flib%2Fmenu_options.php
|
77 |
$viewLink = wfUtils::siteURLRelative() . '?_wfsf=view&nonce=' . wp_create_nonce('wp-ajax') . '&file=' . urlencode($file);
|
78 |
$stat = stat($fullFile);
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
$perms = substr(sprintf('%o', fileperms($fullFile)), -4);
|
84 |
$files[] = array($file, $fullFile, $stat['size'], $stat['mtime'], $viewLink, $owner, $group, $perms);
|
85 |
}
|
76 |
// http://test3.com/?_wfsf=view&nonce=c1ad72bcbd&file=wp-content%2Fplugins%2Fwordfence%2Flib%2Fmenu_options.php
|
77 |
$viewLink = wfUtils::siteURLRelative() . '?_wfsf=view&nonce=' . wp_create_nonce('wp-ajax') . '&file=' . urlencode($file);
|
78 |
$stat = stat($fullFile);
|
79 |
+
if(function_exists('posix_getpwuid')){
|
80 |
+
$owner = posix_getpwuid($stat['uid']);
|
81 |
+
$owner = $owner['name'];
|
82 |
+
} else {
|
83 |
+
$owner = "unknown";
|
84 |
+
}
|
85 |
+
if(function_exists('posix_getgrgid')){
|
86 |
+
$group = posix_getgrgid($stat['gid']);
|
87 |
+
$group = $group['name'];
|
88 |
+
} else {
|
89 |
+
$group = 'unknown';
|
90 |
+
}
|
91 |
$perms = substr(sprintf('%o', fileperms($fullFile)), -4);
|
92 |
$files[] = array($file, $fullFile, $stat['size'], $stat['mtime'], $viewLink, $owner, $group, $perms);
|
93 |
}
|
lib/viewFullActivityLog.php
CHANGED
@@ -14,9 +14,10 @@ global $wpdb;
|
|
14 |
$debugOn = wfConfig::get('debugOn', 0);
|
15 |
$table = $wpdb->base_prefix . 'wfStatus';
|
16 |
$q = $db->query("select ctime, level, type, msg from $table order by ctime desc");
|
|
|
17 |
while($r = mysql_fetch_assoc($q)){
|
18 |
if($r['level'] < 4 || $debugOn){
|
19 |
-
echo '<div' . ($r['type'] == 'error' ? ' class="error"' : '') . '>[' . date('M d H:i:s', $r['ctime']) . ':' . $r['ctime'] . ':' . $r['level'] . ':' . $r['type'] . '] ' . htmlspecialchars($r['msg']) . "</div>\n";
|
20 |
}
|
21 |
}
|
22 |
?>
|
14 |
$debugOn = wfConfig::get('debugOn', 0);
|
15 |
$table = $wpdb->base_prefix . 'wfStatus';
|
16 |
$q = $db->query("select ctime, level, type, msg from $table order by ctime desc");
|
17 |
+
$timeOffset = 3600 * get_option('gmt_offset');
|
18 |
while($r = mysql_fetch_assoc($q)){
|
19 |
if($r['level'] < 4 || $debugOn){
|
20 |
+
echo '<div' . ($r['type'] == 'error' ? ' class="error"' : '') . '>[' . date('M d H:i:s', $r['ctime'] + $timeOffset) . ':' . $r['ctime'] . ':' . $r['level'] . ':' . $r['type'] . '] ' . htmlspecialchars($r['msg']) . "</div>\n";
|
21 |
}
|
22 |
}
|
23 |
?>
|
lib/wfLog.php
CHANGED
@@ -486,7 +486,25 @@ class wfLog {
|
|
486 |
}
|
487 |
public function firewallBadIPs(){
|
488 |
$blockedCountries = wfConfig::get('cbl_countries', false);
|
489 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
490 |
if(is_user_logged_in() && (! wfConfig::get('cbl_loggedInBlocked', false)) ){ //User is logged in and we're allowing logins
|
491 |
//Do nothing
|
492 |
} else if(strpos($_SERVER['REQUEST_URI'], '/wp-login.php') !== false && (! wfConfig::get('cbl_loginFormBlocked', false)) ){ //It's the login form and we're allowing that
|
@@ -494,10 +512,10 @@ class wfLog {
|
|
494 |
} else {
|
495 |
if($country = wfUtils::IP2Country(wfUtils::getIP()) ){
|
496 |
foreach(explode(',', $blockedCountries) as $blocked){
|
497 |
-
if(strtoupper($blocked) == strtoupper($country)){
|
498 |
if(wfConfig::get('cbl_action') == 'redir'){
|
499 |
$redirURL = wfConfig::get('cbl_redirURL');
|
500 |
-
if(wfUtils::extractBareURI($redirURL) ==
|
501 |
//Do nothing
|
502 |
/* Uncomment the following if page components aren't loading for the page we redirect to.
|
503 |
Uncommenting is not recommended because it means that anyone from a blocked country
|
@@ -526,6 +544,23 @@ class wfLog {
|
|
526 |
$this->do503($secsToGo, $rec['reason']);
|
527 |
}
|
528 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
529 |
private function takeBlockingAction($configVar, $reason){
|
530 |
if($this->googleSafetyCheckOK()){
|
531 |
$action = wfConfig::get($configVar . '_action');
|
@@ -617,9 +652,10 @@ class wfLog {
|
|
617 |
$res = $this->getDB()->query("select ctime, level, type, msg from " . $this->statusTable . " where ctime > %f order by ctime asc", $lastCtime);
|
618 |
$results = array();
|
619 |
$lastTime = false;
|
|
|
620 |
while($rec = mysql_fetch_assoc($res)){
|
621 |
//$rec['timeAgo'] = wfUtils::makeTimeAgo(time() - $rec['ctime']);
|
622 |
-
$rec['date'] = date('M d H:i:s', $rec['ctime']);
|
623 |
array_push($results, $rec);
|
624 |
}
|
625 |
return $results;
|
@@ -628,8 +664,9 @@ class wfLog {
|
|
628 |
$res = $this->getDB()->query("select ctime, level, type, msg from " . $this->statusTable . " where level = 10 order by ctime desc limit 100");
|
629 |
$results = array();
|
630 |
$lastTime = false;
|
|
|
631 |
while($rec = mysql_fetch_assoc($res)){
|
632 |
-
$rec['date'] = date('M d H:i:s', $rec['ctime']);
|
633 |
array_push($results, $rec);
|
634 |
if(strpos($rec['msg'], 'SUM_PREP:') === 0){
|
635 |
break;
|
486 |
}
|
487 |
public function firewallBadIPs(){
|
488 |
$blockedCountries = wfConfig::get('cbl_countries', false);
|
489 |
+
$bareRequestURI = wfUtils::extractBareURI($_SERVER['REQUEST_URI']);
|
490 |
+
$bareBypassRedirURI = wfUtils::extractBareURI(wfConfig::get('cbl_bypassRedirURL', ''));
|
491 |
+
$skipCountryBlocking = false;
|
492 |
+
|
493 |
+
if($bareBypassRedirURI && $bareRequestURI == $bareBypassRedirURI){ //Run this before country blocking because even if the user isn't blocked we need to set the bypass cookie so they can bypass future blocks.
|
494 |
+
$bypassRedirDest = wfConfig::get('cbl_bypassRedirDest', '');
|
495 |
+
if($bypassRedirDest){
|
496 |
+
self::setCBLCookieBypass();
|
497 |
+
$this->redirect($bypassRedirDest); //exits
|
498 |
+
}
|
499 |
+
}
|
500 |
+
$bareBypassViewURI = wfUtils::extractBareURI(wfConfig::get('cbl_bypassViewURL', ''));
|
501 |
+
if($bareBypassViewURI && $bareBypassViewURI == $bareRequestURI){
|
502 |
+
self::setCBLCookieBypass();
|
503 |
+
$skipCountryBlocking = true;
|
504 |
+
}
|
505 |
+
|
506 |
+
|
507 |
+
if((! $skipCountryBlocking) && $blockedCountries && wfConfig::get('isPaid') && (! self::isCBLBypassCookieSet()) ){
|
508 |
if(is_user_logged_in() && (! wfConfig::get('cbl_loggedInBlocked', false)) ){ //User is logged in and we're allowing logins
|
509 |
//Do nothing
|
510 |
} else if(strpos($_SERVER['REQUEST_URI'], '/wp-login.php') !== false && (! wfConfig::get('cbl_loginFormBlocked', false)) ){ //It's the login form and we're allowing that
|
512 |
} else {
|
513 |
if($country = wfUtils::IP2Country(wfUtils::getIP()) ){
|
514 |
foreach(explode(',', $blockedCountries) as $blocked){
|
515 |
+
if(strtoupper($blocked) == strtoupper($country)){ //At this point we know the user has been blocked
|
516 |
if(wfConfig::get('cbl_action') == 'redir'){
|
517 |
$redirURL = wfConfig::get('cbl_redirURL');
|
518 |
+
if(wfUtils::extractBareURI($redirURL) == $bareRequestURI){ //Is this the URI we want to redirect to, then don't block it
|
519 |
//Do nothing
|
520 |
/* Uncomment the following if page components aren't loading for the page we redirect to.
|
521 |
Uncommenting is not recommended because it means that anyone from a blocked country
|
544 |
$this->do503($secsToGo, $rec['reason']);
|
545 |
}
|
546 |
}
|
547 |
+
public function getCBLCookieVal(){
|
548 |
+
$val = wfConfig::get('cbl_cookieVal', false);
|
549 |
+
if(! $val){
|
550 |
+
$val = uniqid();
|
551 |
+
wfConfig::set('cbl_cookieVal', $val);
|
552 |
+
}
|
553 |
+
return $val;
|
554 |
+
}
|
555 |
+
public function setCBLCookieBypass(){
|
556 |
+
@setcookie('wfCBLBypass', self::getCBLCookieVal(), time() + (86400 * 365), '/');
|
557 |
+
}
|
558 |
+
public function isCBLBypassCookieSet(){
|
559 |
+
if(isset($_COOKIE['wfCBLBypass']) && $_COOKIE['wfCBLBypass'] == wfConfig::get('cbl_cookieVal')){
|
560 |
+
return true;
|
561 |
+
}
|
562 |
+
return false;
|
563 |
+
}
|
564 |
private function takeBlockingAction($configVar, $reason){
|
565 |
if($this->googleSafetyCheckOK()){
|
566 |
$action = wfConfig::get($configVar . '_action');
|
652 |
$res = $this->getDB()->query("select ctime, level, type, msg from " . $this->statusTable . " where ctime > %f order by ctime asc", $lastCtime);
|
653 |
$results = array();
|
654 |
$lastTime = false;
|
655 |
+
$timeOffset = 3600 * get_option('gmt_offset');
|
656 |
while($rec = mysql_fetch_assoc($res)){
|
657 |
//$rec['timeAgo'] = wfUtils::makeTimeAgo(time() - $rec['ctime']);
|
658 |
+
$rec['date'] = date('M d H:i:s', $rec['ctime'] + $timeOffset);
|
659 |
array_push($results, $rec);
|
660 |
}
|
661 |
return $results;
|
664 |
$res = $this->getDB()->query("select ctime, level, type, msg from " . $this->statusTable . " where level = 10 order by ctime desc limit 100");
|
665 |
$results = array();
|
666 |
$lastTime = false;
|
667 |
+
$timeOffset = 3600 * get_option('gmt_offset');
|
668 |
while($rec = mysql_fetch_assoc($res)){
|
669 |
+
$rec['date'] = date('M d H:i:s', $rec['ctime'] + $timeOffset);
|
670 |
array_push($results, $rec);
|
671 |
if(strpos($rec['msg'], 'SUM_PREP:') === 0){
|
672 |
break;
|
lib/wfUtils.php
CHANGED
@@ -452,6 +452,9 @@ class wfUtils {
|
|
452 |
$URL = rtrim($URL, '/') . '/';
|
453 |
return $URL;
|
454 |
}
|
|
|
|
|
|
|
455 |
|
456 |
}
|
457 |
|
452 |
$URL = rtrim($URL, '/') . '/';
|
453 |
return $URL;
|
454 |
}
|
455 |
+
public static function localHumanDate(){
|
456 |
+
return date('l jS \of F Y \a\t h:i:s A', time() + (3600 * get_option('gmt_offset')));
|
457 |
+
}
|
458 |
|
459 |
}
|
460 |
|
lib/wordfenceClass.php
CHANGED
@@ -617,6 +617,7 @@ class wordfence {
|
|
617 |
$secondsInFuture += (86400 * 7); //Add a week
|
618 |
}
|
619 |
$futureTime = time() - (time() % 3600) + $secondsInFuture; //Modulo rounds down to top of the hour
|
|
|
620 |
wordfence::status(4, 'info', "Scheduled time for day $scheduledDay hour $scheduledHour is: " . date('l jS \of F Y h:i:s A', $futureTime));
|
621 |
self::scheduleSingleScan($futureTime);
|
622 |
}
|
@@ -650,6 +651,9 @@ class wordfence {
|
|
650 |
wfConfig::set('cbl_redirURL', $_POST['redirURL']);
|
651 |
wfConfig::set('cbl_loggedInBlocked', $_POST['loggedInBlocked']);
|
652 |
wfConfig::set('cbl_loginFormBlocked', $_POST['loginFormBlocked']);
|
|
|
|
|
|
|
653 |
return array('ok' => 1);
|
654 |
}
|
655 |
public static function ajax_sendActivityLog_callback(){
|
@@ -658,11 +662,12 @@ class wordfence {
|
|
658 |
global $wpdb;
|
659 |
$p = $wpdb->base_prefix;
|
660 |
$q = $wfdb->query("select ctime, level, type, msg from $p"."wfStatus order by ctime desc limit 10000");
|
|
|
661 |
while($r = mysql_fetch_assoc($q)){
|
662 |
if($r['type'] == 'error'){
|
663 |
$content .= "\n";
|
664 |
}
|
665 |
-
$content .= date(DATE_RFC822, $r['ctime']) . '::' . sprintf('%.4f', $r['ctime']) . ':' . $r['level'] . ':' . $r['type'] . '::' . $r['msg'] . "\n";
|
666 |
}
|
667 |
$content .= "\n\n";
|
668 |
|
@@ -1270,7 +1275,7 @@ class wordfence {
|
|
1270 |
$wp->add_query_var('_wfsf');
|
1271 |
//add_rewrite_rule('wfStaticFunc/([a-zA-Z0-9]+)/?$', 'index.php?wfStaticFunc=' . $matches[1], 'top');
|
1272 |
$cookieName = 'wfvt_' . crc32(site_url());
|
1273 |
-
$c = isset($
|
1274 |
if($c){
|
1275 |
self::$newVisit = false;
|
1276 |
} else {
|
@@ -1447,7 +1452,7 @@ class wordfence {
|
|
1447 |
'blogName' => get_bloginfo('name', 'raw'),
|
1448 |
'alertMsg' => $alertMsg,
|
1449 |
'IPMsg' => $IPMsg,
|
1450 |
-
'date' =>
|
1451 |
'myHomeURL' => self::getMyHomeURL(),
|
1452 |
'myOptionsURL' => self::getMyOptionsURL()
|
1453 |
));
|
617 |
$secondsInFuture += (86400 * 7); //Add a week
|
618 |
}
|
619 |
$futureTime = time() - (time() % 3600) + $secondsInFuture; //Modulo rounds down to top of the hour
|
620 |
+
$futureTime += rand(0,3600); //Prevent a stampede of scans on our scanning server
|
621 |
wordfence::status(4, 'info', "Scheduled time for day $scheduledDay hour $scheduledHour is: " . date('l jS \of F Y h:i:s A', $futureTime));
|
622 |
self::scheduleSingleScan($futureTime);
|
623 |
}
|
651 |
wfConfig::set('cbl_redirURL', $_POST['redirURL']);
|
652 |
wfConfig::set('cbl_loggedInBlocked', $_POST['loggedInBlocked']);
|
653 |
wfConfig::set('cbl_loginFormBlocked', $_POST['loginFormBlocked']);
|
654 |
+
wfConfig::set('cbl_bypassRedirURL', $_POST['bypassRedirURL']);
|
655 |
+
wfConfig::set('cbl_bypassRedirDest', $_POST['bypassRedirDest']);
|
656 |
+
wfConfig::set('cbl_bypassViewURL', $_POST['bypassViewURL']);
|
657 |
return array('ok' => 1);
|
658 |
}
|
659 |
public static function ajax_sendActivityLog_callback(){
|
662 |
global $wpdb;
|
663 |
$p = $wpdb->base_prefix;
|
664 |
$q = $wfdb->query("select ctime, level, type, msg from $p"."wfStatus order by ctime desc limit 10000");
|
665 |
+
$timeOffset = 3600 * get_option('gmt_offset');
|
666 |
while($r = mysql_fetch_assoc($q)){
|
667 |
if($r['type'] == 'error'){
|
668 |
$content .= "\n";
|
669 |
}
|
670 |
+
$content .= date(DATE_RFC822, $r['ctime'] + $timeOffset) . '::' . sprintf('%.4f', $r['ctime']) . ':' . $r['level'] . ':' . $r['type'] . '::' . $r['msg'] . "\n";
|
671 |
}
|
672 |
$content .= "\n\n";
|
673 |
|
1275 |
$wp->add_query_var('_wfsf');
|
1276 |
//add_rewrite_rule('wfStaticFunc/([a-zA-Z0-9]+)/?$', 'index.php?wfStaticFunc=' . $matches[1], 'top');
|
1277 |
$cookieName = 'wfvt_' . crc32(site_url());
|
1278 |
+
$c = isset($_COOKIE[$cookieName]) ? isset($_COOKIE[$cookieName]) : false;
|
1279 |
if($c){
|
1280 |
self::$newVisit = false;
|
1281 |
} else {
|
1452 |
'blogName' => get_bloginfo('name', 'raw'),
|
1453 |
'alertMsg' => $alertMsg,
|
1454 |
'IPMsg' => $IPMsg,
|
1455 |
+
'date' => wfUtils::localHumanDate(),
|
1456 |
'myHomeURL' => self::getMyHomeURL(),
|
1457 |
'myOptionsURL' => self::getMyOptionsURL()
|
1458 |
));
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: mmaunder
|
|
3 |
Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
|
4 |
Requires at least: 3.3.1
|
5 |
Tested up to: 3.4.1
|
6 |
-
Stable tag: 3.2.
|
7 |
|
8 |
Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
|
9 |
|
@@ -153,6 +153,13 @@ or a theme, because often these have been updated to fix a security hole.
|
|
153 |
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
|
154 |
|
155 |
== Changelog ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
= 3.2.6 =
|
157 |
* Paid feature: Remote site vulnerability and infection scanning.
|
158 |
|
3 |
Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
|
4 |
Requires at least: 3.3.1
|
5 |
Tested up to: 3.4.1
|
6 |
+
Stable tag: 3.2.7
|
7 |
|
8 |
Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
|
9 |
|
153 |
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
|
154 |
|
155 |
== Changelog ==
|
156 |
+
= 3.2.7 =
|
157 |
+
* Fixed dates and times in activity log alert emails and other emails to be in site's local timezone.
|
158 |
+
* Added advanced country blocking options which allow bypass if a special URL is hit.
|
159 |
+
* Added warning in options page if alert email is not configured under alert checkboxes.
|
160 |
+
* Modified scan times to be within 60 minute window after scheduled time to prevent stampede at the top of the hour on our scanning server.
|
161 |
+
* Fixed bug on Godaddy and a few other hosts where viewing list of files not in the repo caused error. This was caused by posix functions not being supported on Godaddy and some other hosts.
|
162 |
+
|
163 |
= 3.2.6 =
|
164 |
* Paid feature: Remote site vulnerability and infection scanning.
|
165 |
|
wordfence.php
CHANGED
@@ -4,10 +4,10 @@ Plugin Name: Wordfence Security
|
|
4 |
Plugin URI: http://wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
-
Version: 3.2.
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
-
define('WORDFENCE_VERSION', '3.2.
|
11 |
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
|
12 |
if((int) @ini_get('memory_limit') < 64){
|
13 |
@ini_set('memory_limit', '64M'); //Some hosts have ini set at as little as 32 megs. 64 is the min sane amount of memory.
|
4 |
Plugin URI: http://wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
+
Version: 3.2.7
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
+
define('WORDFENCE_VERSION', '3.2.7');
|
11 |
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
|
12 |
if((int) @ini_get('memory_limit') < 64){
|
13 |
@ini_set('memory_limit', '64M'); //Some hosts have ini set at as little as 32 megs. 64 is the min sane amount of memory.
|