rebase from live enviornment
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+37
@@ -466,6 +466,10 @@
|
||||
value = optionElement.data('enabledToggleValue');
|
||||
}
|
||||
|
||||
if (option === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var originalValue = optionElement.data('originalToggleValue');
|
||||
if (originalValue == value) {
|
||||
delete WFAD.pendingChanges[option];
|
||||
@@ -510,6 +514,10 @@
|
||||
var optionElement = $(this).closest('.wf-option');
|
||||
var option = optionElement.data('selectOption');
|
||||
var value = $(this).val();
|
||||
|
||||
if (option === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var originalValue = optionElement.data('originalSelectValue');
|
||||
if (originalValue == value) {
|
||||
@@ -820,6 +828,35 @@
|
||||
}
|
||||
});
|
||||
},
|
||||
wordfenceSatisfactionChoice: function(choice) {
|
||||
if (choice == 'yes') {
|
||||
$('#wordfenceSatisfactionPrompt-yes').slideDown(400, function() {
|
||||
$('#wordfenceSatisfactionPrompt-initial .wf-btn').addClass('wf-disabled').css('opacity', 0.3);
|
||||
$('#wordfenceSatisfactionPrompt-initial .wf-btn:first-of-type').css('opacity', 0.8);
|
||||
});
|
||||
WFAD.ajax('wordfence_wordfenceSatisfactionChoice', {choice: choice});
|
||||
}
|
||||
else if (choice == 'no') {
|
||||
$('#wordfenceSatisfactionPrompt-no').slideDown(400, function() {
|
||||
$('#wordfenceSatisfactionPrompt-initial .wf-btn').addClass('wf-disabled').css('opacity', 0.3);
|
||||
$('#wordfenceSatisfactionPrompt-initial .wf-btn:last-of-type').css('opacity', 0.8);
|
||||
});
|
||||
WFAD.ajax('wordfence_wordfenceSatisfactionChoice', {choice: choice});
|
||||
}
|
||||
else if (choice == 'feedback') {
|
||||
WFAD.ajax('wordfence_wordfenceSatisfactionChoice', {
|
||||
choice: choice,
|
||||
feedback: $('#wordfenceSatisfactionPrompt-feedback').val(),
|
||||
},
|
||||
function(res) { $('#wordfenceSatisfactionPrompt-no').fadeOut(); $('#wordfenceSatisfactionPrompt-complete').fadeIn(); },
|
||||
function() { $('#wordfenceSatisfactionPrompt-no').fadeOut(); $('#wordfenceSatisfactionPrompt-complete').fadeIn(); }
|
||||
);
|
||||
}
|
||||
else if (choice == 'dismiss') {
|
||||
$('#wordfenceSatisfactionPrompt').fadeOut();
|
||||
WFAD.ajax('wordfence_wordfenceSatisfactionChoice', {choice: choice});
|
||||
}
|
||||
},
|
||||
tourFinish: function(page) {
|
||||
if (WFAD.currentPointer) {
|
||||
WFAD.currentPointer.pointer('destroy');
|
||||
File diff suppressed because it is too large
Load Diff
@@ -234,7 +234,12 @@ if (!isset($sendingDiagnosticEmail)) {
|
||||
<?php endforeach ?>
|
||||
<tr>
|
||||
<td><?php esc_html_e('Trusted Proxies', 'wordfence'); ?></td>
|
||||
<td><?php echo esc_html(implode(', ', explode("\n", wfConfig::get('howGetIPs_trusted_proxies', '')))); ?></td>
|
||||
<td><?php $proxies = wfConfig::get('howGetIPs_trusted_proxies', ''); echo esc_html(implode(', ', explode("\n", empty($proxies) ? __('(not set)', 'wordfence') : $proxies))); ?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php esc_html_e('Trusted Proxy Preset', 'wordfence'); ?></td>
|
||||
<td><?php $preset = wfConfig::get('howGetIPs_trusted_proxy_preset'); $presets = wfConfig::getJSON('ipResolutionList', array()); echo esc_html((is_array($presets) && isset($presets[$preset])) ? $presets[$preset]['name'] : __('(not set)', 'wordfence')); ?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -524,8 +529,8 @@ if (!isset($sendingDiagnosticEmail)) {
|
||||
global $wpdb;
|
||||
$wfdb = new wfDB();
|
||||
//This must be done this way because MySQL with InnoDB tables does a full regeneration of all metadata if we don't. That takes a long time with a large table count.
|
||||
$tables = $wfdb->querySelect('SELECT SQL_CALC_FOUND_ROWS TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() ORDER BY TABLE_NAME ASC LIMIT 250');
|
||||
$total = $wfdb->querySingle('SELECT FOUND_ROWS()');
|
||||
$tables = $wfdb->querySelect('SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() ORDER BY TABLE_NAME ASC LIMIT 250');
|
||||
$total = $wfdb->querySingle('SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE()');
|
||||
foreach ($tables as &$t) {
|
||||
$t = "'" . esc_sql($t['TABLE_NAME']) . "'";
|
||||
}
|
||||
@@ -548,7 +553,7 @@ if (!isset($sendingDiagnosticEmail)) {
|
||||
</div>
|
||||
<div class="wf-block-content wf-clearfix wf-padding-no-left wf-padding-no-right">
|
||||
<ul class="wf-block-list wf-padding-add-left-large wf-padding-add-right-large">
|
||||
<li style="border-bottom: 1px solid #e2e2e2;">
|
||||
<li>
|
||||
<div style="width: 75%; min-width: 300px;"><?php esc_html_e('Wordfence Table Check', 'wordfence'); ?></div>
|
||||
<div class="wf-right">
|
||||
<?php if ($total > 250): ?>
|
||||
@@ -590,6 +595,12 @@ if (!isset($sendingDiagnosticEmail)) {
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</li>
|
||||
<li style="border-bottom: 1px solid #e2e2e2;">
|
||||
<div style="width: 75%; min-width: 300px;"><?php esc_html_e('Number of Database Tables', 'wordfence'); ?></div>
|
||||
<div class="wf-right">
|
||||
<div class="wf-result-info"><?php echo esc_html( $total ); ?></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="wf-add-top-large" style="max-width: 100%; overflow: auto; padding: 1px;">
|
||||
<table class="wf-striped-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
|
||||
@@ -906,4 +917,4 @@ if (!isset($sendingDiagnosticEmail)) {
|
||||
'secondaryButtons' => array(array('id' => 'wf-restore-defaults-prompt-confirm', 'labelHTML' => wp_kses(/* translators: word order may be reversed as long as HTML remains around "Defaults" */ __('Restore<span class="wf-hidden-xs"> Defaults</span>', 'wordfence'), array('span'=>array('class'=>array()))), 'link' => '#')),
|
||||
))->render();
|
||||
?>
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -567,6 +567,8 @@ class wfCentral {
|
||||
$scan = array();
|
||||
}
|
||||
}
|
||||
|
||||
wfScanner::shared()->flushSummaryItems();
|
||||
|
||||
$siteID = wfConfig::get('wordfenceCentralSiteID');
|
||||
$running = wfScanner::shared()->isRunning();
|
||||
|
||||
@@ -176,6 +176,7 @@ class wfConfig {
|
||||
'wafAlertInterval' => array('value' => 600, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
|
||||
'wafAlertThreshold' => array('value' => 100, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
|
||||
'howGetIPs_trusted_proxies' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
|
||||
'howGetIPs_trusted_proxy_preset' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
|
||||
'scanType' => array('value' => wfScanner::SCAN_TYPE_STANDARD, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
|
||||
'manualScanType' => array('value' => wfScanner::MANUAL_SCHEDULING_ONCE_DAILY, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
|
||||
'schedStartHour' => array('value' => -1, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
|
||||
@@ -227,6 +228,9 @@ class wfConfig {
|
||||
'lastPermissionsTemplateCheck' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
|
||||
'previousWflogsFileList' => array('value' => '[]', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
|
||||
'diagnosticsWflogsRemovalHistory' => array('value' => '[]', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
|
||||
'satisfactionPromptDismissed' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
|
||||
'satisfactionPromptInstallDate' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
|
||||
'satisfactionPromptOverride' => array('value' => true, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
|
||||
),
|
||||
);
|
||||
public static $serializedOptions = array('lastAdminLogin', 'scanSched', 'emailedIssuesList', 'wf_summaryItems', 'adminUserList', 'twoFactorUsers', 'alertFreqTrack', 'wfStatusStartMsgs', 'vulnerabilities_plugin', 'vulnerabilities_theme', 'dashboardData', 'malwarePrefixes', 'coreHashes', 'noc1ScanSchedule', 'allScansScheduled', 'disclosureStates', 'scanStageStatuses', 'adminNoticeQueue', 'suspiciousAdminUsernames', 'wordpressPluginVersions', 'wordpressThemeVersions');
|
||||
@@ -517,6 +521,9 @@ class wfConfig {
|
||||
public static function setJSON($key, $val, $autoload = self::AUTOLOAD) {
|
||||
self::set($key, @json_encode($val), $autoload);
|
||||
}
|
||||
public static function setBool($key, $val, $autoload = self::AUTOLOAD) {
|
||||
self::set($key, wfUtils::truthyToBoolean($val) ? 1 : 0, $autoload);
|
||||
}
|
||||
public static function setOrRemove($key, $value, $autoload = self::AUTOLOAD) {
|
||||
if ($value === null) {
|
||||
self::remove($key);
|
||||
@@ -564,6 +571,10 @@ class wfConfig {
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
public static function getBool($key, $default = false, $allowCached = true) {
|
||||
return wfUtils::truthyToBoolean(self::get($key, $default, $allowCached));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a test against the database to verify set_ser is working via MySQLi.
|
||||
*
|
||||
@@ -1309,6 +1320,21 @@ Options -ExecCGI
|
||||
$checked = true;
|
||||
break;
|
||||
}
|
||||
case 'howGetIPs_trusted_proxy_preset':
|
||||
{
|
||||
$presets = wfConfig::getJSON('ipResolutionList', array());
|
||||
if (!is_array($presets)) {
|
||||
$presets = array();
|
||||
}
|
||||
|
||||
if (!(empty($value) /* "None" */ || isset($presets[$value]))) {
|
||||
$errors[] = array('option' => $key, 'error' => __('The selected trusted proxy preset is not valid: ', 'wordfence') . esc_html($value));
|
||||
}
|
||||
|
||||
$checked = true;
|
||||
|
||||
break;
|
||||
}
|
||||
case 'apiKey':
|
||||
{
|
||||
$value = trim($value);
|
||||
@@ -1830,7 +1856,7 @@ Options -ExecCGI
|
||||
$api = new wfAPI($apiKey, wfUtils::getWPVersion());
|
||||
try {
|
||||
$keyType = wfLicense::KEY_TYPE_FREE;
|
||||
$keyData = $api->call('ping_api_key', array(), array('supportHash' => wfConfig::get('supportHash', ''), 'whitelistHash' => wfConfig::get('whitelistHash', ''), 'tldlistHash' => wfConfig::get('tldlistHash', '')));
|
||||
$keyData = $api->call('ping_api_key', array(), array('supportHash' => wfConfig::get('supportHash', ''), 'whitelistHash' => wfConfig::get('whitelistHash', ''), 'tldlistHash' => wfConfig::get('tldlistHash', ''), 'ipResolutionListHash' => wfConfig::get('ipResolutionListHash', '')));
|
||||
if (isset($keyData['_isPaidKey'])) {
|
||||
$keyType = wfConfig::get('keyType');
|
||||
}
|
||||
@@ -1850,6 +1876,10 @@ Options -ExecCGI
|
||||
wfConfig::set('tldlist', $keyData['_tldlist']);
|
||||
wfConfig::set('tldlistHash', $keyData['_tldlistHash']);
|
||||
}
|
||||
if (isset($keyData['_ipResolutionList']) && isset($keyData['_ipResolutionListHash'])) {
|
||||
wfConfig::setJSON('ipResolutionList', $keyData['_ipResolutionList']);
|
||||
wfConfig::set('ipResolutionListHash', $keyData['_ipResolutionListHash']);
|
||||
}
|
||||
if (isset($keyData['scanSchedule']) && is_array($keyData['scanSchedule'])) {
|
||||
wfConfig::set_ser('noc1ScanSchedule', $keyData['scanSchedule']);
|
||||
if (wfScanner::shared()->schedulingMode() == wfScanner::SCAN_SCHEDULING_MODE_AUTOMATIC) {
|
||||
@@ -1910,6 +1940,7 @@ Options -ExecCGI
|
||||
'email_summary_interval',
|
||||
'email_summary_excluded_directories',
|
||||
'howGetIPs_trusted_proxies',
|
||||
'howGetIPs_trusted_proxy_preset',
|
||||
'displayTopLevelOptions',
|
||||
);
|
||||
break;
|
||||
@@ -2075,6 +2106,7 @@ Options -ExecCGI
|
||||
'email_summary_interval',
|
||||
'email_summary_excluded_directories',
|
||||
'howGetIPs_trusted_proxies',
|
||||
'howGetIPs_trusted_proxy_preset',
|
||||
'firewallEnabled',
|
||||
'autoBlockScanners',
|
||||
'loginSecurityEnabled',
|
||||
|
||||
@@ -92,7 +92,11 @@ class wfDiagnostic
|
||||
'wafAutoPrependFilePath' => __('wordfence-waf.php path', 'wordfence'),
|
||||
'wafFilePermissions' => __('WAF File Permissions', 'wordfence'),
|
||||
'wafRecentlyRemoved' => __('Recently removed wflogs files', 'wordfence'),
|
||||
'wafLoaded' => __('WAF Loaded Successfully', 'wordfence')
|
||||
'wafLoaded' => __('WAF Loaded Successfully', 'wordfence'),
|
||||
'wafAutoPrependHtaccess' => __('WAF .htaccess contents', 'wordfence'),
|
||||
'wafAutoPrependUserIni' => __('WAF .user.ini contents', 'wordfence'),
|
||||
'wafAutoPrependHtaccessOther' => __('.htaccess other auto prepend', 'wordfence'),
|
||||
'wafAutoPrependUserIniOther' => __('.user.ini other auto prepend', 'wordfence'),
|
||||
),
|
||||
),
|
||||
'MySQL' => array(
|
||||
@@ -362,6 +366,78 @@ class wfDiagnostic
|
||||
public function wafAutoPrepend() {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => (defined('WFWAF_AUTO_PREPEND') && WFWAF_AUTO_PREPEND ? __('Yes', 'wordfence') : __('No', 'wordfence')));
|
||||
}
|
||||
public function wafAutoPrependHtaccess() {
|
||||
$htaccessPath = wfWAFAutoPrependHelper::getHtaccessPath();
|
||||
if (!file_exists($htaccessPath)) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(.htaccess not present)', 'wordfence'));
|
||||
}
|
||||
else if (!is_readable($htaccessPath)) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(.htaccess not readable)', 'wordfence'));
|
||||
}
|
||||
|
||||
$htaccessContents = file_get_contents($htaccessPath);
|
||||
$section = wfWAFAutoPrependHelper::getHtaccessSectionContent($htaccessContents);
|
||||
if ($section === false) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(not set)', 'wordfence'));
|
||||
}
|
||||
|
||||
$snippet = wfUtils::pregExtract("/auto_prepend_file\s+['\"]?[^'\"]*['\"]?/", $section);
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => $snippet, 'detail' => array('escaped' => nl2br(esc_html($section)), 'textonly' => $section));
|
||||
}
|
||||
public function wafAutoPrependHtaccessOther() {
|
||||
$htaccessPath = wfWAFAutoPrependHelper::getHtaccessPath();
|
||||
if (!file_exists($htaccessPath)) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(.htaccess not present)', 'wordfence'));
|
||||
}
|
||||
else if (!is_readable($htaccessPath)) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(.htaccess not readable)', 'wordfence'));
|
||||
}
|
||||
|
||||
$htaccessContents = file_get_contents($htaccessPath);
|
||||
$section = wfWAFAutoPrependHelper::getHtaccessSectionContent($htaccessContents);
|
||||
if ($section !== false) {
|
||||
$htaccessContents = str_replace($section, '', $htaccessContents);
|
||||
}
|
||||
|
||||
$snippet = wfUtils::pregExtract("/auto_prepend_file\s+['\"]?[^'\"]*['\"]?/", $htaccessContents, true);
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => ($snippet === false ? __('(not present)', 'wordfence') : trim($snippet)));
|
||||
}
|
||||
public function wafAutoPrependUserIni() {
|
||||
$userIniPath = wfWAFAutoPrependHelper::getUserIniPath();
|
||||
if (!file_exists($userIniPath)) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(.user.ini not present)', 'wordfence'));
|
||||
}
|
||||
else if (!is_readable($userIniPath)) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(.user.ini not readable)', 'wordfence'));
|
||||
}
|
||||
|
||||
$userIniContents = file_get_contents($userIniPath);
|
||||
$section = wfWAFAutoPrependHelper::getUserIniSectionContent($userIniContents);
|
||||
if ($section === false) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(not set)', 'wordfence'));
|
||||
}
|
||||
|
||||
$snippet = wfUtils::pregExtract("/auto_prepend_file\s*=\s*['\"]?[^'\"]*['\"]?/", $section);
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => $snippet, 'detail' => $section);
|
||||
}
|
||||
public function wafAutoPrependUserIniOther() {
|
||||
$userIniPath = wfWAFAutoPrependHelper::getUserIniPath();
|
||||
if (!file_exists($userIniPath)) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(.user.ini not present)', 'wordfence'));
|
||||
}
|
||||
else if (!is_readable($userIniPath)) {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => __('(.user.ini not readable)', 'wordfence'));
|
||||
}
|
||||
|
||||
$userIniContents = file_get_contents($userIniPath);
|
||||
$section = wfWAFAutoPrependHelper::getUserIniSectionContent($userIniContents);
|
||||
if ($section !== false) {
|
||||
$userIniContents = str_replace($section, '', $userIniContents);
|
||||
}
|
||||
|
||||
$snippet = wfUtils::pregExtract("/auto_prepend_file\s*=\s*['\"]?[^'\"]*['\"]?/", $userIniContents, true);
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => ($snippet === false ? __('(not present)', 'wordfence') : trim($snippet)));
|
||||
}
|
||||
public function wafStorageEngine() {
|
||||
return array('test' => true, 'infoOnly' => true, 'message' => (defined('WFWAF_STORAGE_ENGINE') ? WFWAF_STORAGE_ENGINE : __('(default)', 'wordfence')));
|
||||
}
|
||||
@@ -669,13 +745,17 @@ class wfDiagnostic
|
||||
$detail = '';
|
||||
if (is_wp_error($result)) {
|
||||
$message = __('wp_remote_post() test back to this server failed! Response was: ', 'wordfence') . $result->get_error_message();
|
||||
$messageTextOnly = __('wp_remote_post() test back to this server failed! Response was: ', 'wordfence') . $result->get_error_message();
|
||||
}
|
||||
else {
|
||||
$message = __('wp_remote_post() test back to this server failed! Response was: ', 'wordfence') . '<br>' . $result['response']['code'] . " " . $result['response']['message'] . '<br><br>';
|
||||
$message = __('wp_remote_post() test back to this server failed! Response was: ', 'wordfence') . '<br>' . $result['response']['code'] . ' ' . $result['response']['message'] . '<br><br>';
|
||||
$messageTextOnly = __('wp_remote_post() test back to this server failed! Response was: ', 'wordfence') . "\n" . $result['response']['code'] . ' ' . $result['response']['message'] . "\n\n";
|
||||
if ($this->_detectBlockedByCloudflare($result)) {
|
||||
$message .= __('Cloudflare appears to be blocking your site from connecting to itself.', 'wordfence') . '<br>' . sprintf(' <a href="%s" target="_blank" rel="noopener noreferrer">', wfSupportController::esc_supportURL(wfSupportController::ITEM_DIAGNOSTICS_CLOUDFLARE_BLOCK)) . __('Get help with Cloudflare compatibility', 'wordfence') . '</a><br><br>';
|
||||
$messageTextOnly .= __('Cloudflare appears to be blocking your site from connecting to itself.', 'wordfence') . "\n" . __('Get help with Cloudflare compatibility', 'wordfence') . ': ' . wfSupportController::esc_supportURL(wfSupportController::ITEM_DIAGNOSTICS_CLOUDFLARE_BLOCK) . "\n\n";
|
||||
}
|
||||
$message .= __('This additional info may help you diagnose the issue. The response headers we received were:', 'wordfence') . '<br><br>';
|
||||
$messageTextOnly .= __('This additional info may help you diagnose the issue. The response headers we received were:', 'wordfence') . "\n\n";
|
||||
if (isset($result['http_response']) && is_object($result['http_response']) && method_exists($result['http_response'], 'get_response_object') && is_object($result['http_response']->get_response_object()) && property_exists($result['http_response']->get_response_object(), 'raw')) {
|
||||
$detail = str_replace("\r\n", "\n", $result['http_response']->get_response_object()->raw);
|
||||
}
|
||||
@@ -685,7 +765,7 @@ class wfDiagnostic
|
||||
|
||||
return array(
|
||||
'test' => false,
|
||||
'message' => array('escaped' => $message),
|
||||
'message' => array('escaped' => $message, 'textonly' => $messageTextOnly),
|
||||
'detail' => $detail,
|
||||
);
|
||||
}
|
||||
@@ -705,12 +785,13 @@ class wfDiagnostic
|
||||
if ($errorNumber === 6 /* COULDNT_RESOLVE_HOST */) {
|
||||
$detail = sprintf(/* translators: error message from failed request */ __('This likely indicates that the server either does not support IPv6 or does not have an IPv6 address assigned or associated with the domain. Original error message: %s', 'wordfence'), is_array($result['message']) ? $result['message']['escaped'] : $result['message']);
|
||||
$detail = wp_kses($detail, array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()), 'em' => array(), 'code' => array(), 'br' => array()));
|
||||
$detailTextOnly = sprintf(/* translators: error message from failed request */ __('This likely indicates that the server either does not support IPv6 or does not have an IPv6 address assigned or associated with the domain. Original error message: %s', 'wordfence'), is_array($result['message']) ? $result['message']['textonly'] : strip_tags($result['message']));
|
||||
|
||||
return array(
|
||||
'test' => false,
|
||||
'infoOnly' => true,
|
||||
'message' => __('IPv6 DNS resolution failed', 'wordfence'),
|
||||
'detail' => array('escaped' => $detail),
|
||||
'detail' => array('escaped' => $detail, 'textonly' => $detailTextOnly),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,6 +772,7 @@ class wfScanEngine {
|
||||
$this->scanController->startStage(wfScanner::STAGE_PUBLIC_FILES);
|
||||
|
||||
$backupFileTests = array(
|
||||
wfCommonBackupFileTest::createFromRootPath('.env'),
|
||||
wfCommonBackupFileTest::createFromRootPath('.user.ini'),
|
||||
// wfCommonBackupFileTest::createFromRootPath('.htaccess'),
|
||||
wfCommonBackupFileTest::createFromRootPath('wp-config.php.bak'),
|
||||
@@ -2081,7 +2082,17 @@ class wfScanEngine {
|
||||
($lastUpdateTimestamp = strtotime($statusArray['last_updated'])) &&
|
||||
(time() - $lastUpdateTimestamp) > 63072000 /* ~2 years */) {
|
||||
|
||||
$statusArray['dateUpdated'] = wfUtils::formatLocalTime(get_option('date_format'), $lastUpdateTimestamp);
|
||||
try {
|
||||
$statusArray['dateUpdated'] = wfUtils::formatLocalTime(get_option('date_format'), $lastUpdateTimestamp);
|
||||
}
|
||||
catch (Exception $e) { //DateMalformedStringException in PHP >= 8.3, Exception previously
|
||||
wordfence::status(3, 'error', sprintf(
|
||||
/* translators: 1. Plugin slug. 2. Malformed date string. */
|
||||
__('Encountered bad date string for plugin "%s" in abandoned plugin check: %s', 'wordfence'),
|
||||
$slug,
|
||||
$statusArray['last_updated']));
|
||||
continue;
|
||||
}
|
||||
$severity = wfIssues::SEVERITY_MEDIUM;
|
||||
$statusArray['abandoned'] = true;
|
||||
$statusArray['vulnerable'] = false;
|
||||
@@ -2104,7 +2115,7 @@ class wfScanEngine {
|
||||
/* translators: 1. Plugin name. 2. Software version. 3. Software version. */
|
||||
__('The Plugin "%1$s" appears to be abandoned (updated %2$s, tested to WP %3$s).', 'wordfence'),
|
||||
(empty($statusArray['name']) ? $slug : $statusArray['name']),
|
||||
wfUtils::formatLocalTime(get_option('date_format'), $lastUpdateTimestamp),
|
||||
$statusArray['dateUpdated'],
|
||||
$statusArray['tested']
|
||||
);
|
||||
$longMsg = sprintf(
|
||||
@@ -2118,7 +2129,7 @@ class wfScanEngine {
|
||||
/* translators: 1. Plugin name. 2. Software version. */
|
||||
__('The Plugin "%1$s" appears to be abandoned (updated %2$s).', 'wordfence'),
|
||||
(empty($statusArray['name']) ? $slug : $statusArray['name']),
|
||||
wfUtils::formatLocalTime(get_option('date_format'), $lastUpdateTimestamp)
|
||||
$statusArray['dateUpdated']
|
||||
);
|
||||
$longMsg = sprintf(
|
||||
/* translators: Time duration. */
|
||||
@@ -2130,7 +2141,7 @@ class wfScanEngine {
|
||||
if ($statusArray['vulnerable']) {
|
||||
$longMsg .= ' ' . __('It has unpatched security issues and may have compatibility problems with the current version of WordPress.', 'wordfence');
|
||||
} else {
|
||||
$longMsg .= ' ' . __('Your site is still using this plugin, but it is not currently available on wordpress.org. Plugins can be removed from wordpress.org for various reasons. This can include benign issues like a plugin author discontinuing development or moving the plugin distribution to their own site, but some might also be due to security issues. In any case, future updates may or may not be available, so it is worth investigating the cause and deciding whether to temporarily or permanently replace or remove the plugin.', 'wordfence');
|
||||
$longMsg .= ' ' . __('It may have compatibility problems with the current version of WordPress or unknown security issues.', 'wordfence');
|
||||
}
|
||||
$longMsg .= ' ' . sprintf(
|
||||
/* translators: Support URL. */
|
||||
|
||||
@@ -120,8 +120,8 @@ class wfScanMonitor {
|
||||
}
|
||||
|
||||
public static function registerActions() {
|
||||
add_filter('cron_schedules', array(get_class(), 'registerCronInterval'));
|
||||
add_action(self::CRON_HOOK, array(get_class(), 'monitorScan'));
|
||||
add_filter('cron_schedules', array(self::class, 'registerCronInterval'));
|
||||
add_action(self::CRON_HOOK, array(self::class, 'monitorScan'));
|
||||
}
|
||||
|
||||
public static function handleDeactivation() {
|
||||
|
||||
@@ -383,4 +383,56 @@ class wfSupportController {
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function shouldShowSatisfactionPrompt() {
|
||||
//Don't show if overridden
|
||||
if (!wfConfig::getBool('satisfactionPromptOverride')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Only show on our pages
|
||||
if (!isset($_REQUEST['page'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!preg_match('/^Wordfence/', $_REQUEST['page'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Only show until dismissed
|
||||
if (wfConfig::get('satisfactionPromptDismissed') > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Only show to users installing after the release date of the version this was introduced
|
||||
if (WORDFENCE_FEEDBACK_EPOCH > wfConfig::get('satisfactionPromptInstallDate')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Don't show for at least 7 days post-install
|
||||
if ((time() - wfConfig::get('satisfactionPromptInstallDate')) < 86400 * 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function satisfactionPromptNotice() {
|
||||
?>
|
||||
<div id="wordfenceSatisfactionPrompt" class="fade notice notice-info">
|
||||
<p id="wordfenceSatisfactionPrompt-initial"><strong><?php printf(__('Are you enjoying using Wordfence Security?', 'wordfence')); ?></strong> <a href="#" onclick="WFAD.wordfenceSatisfactionChoice('yes'); return false;" class="wf-btn wf-btn-default wf-btn-sm" role="button"><?php printf(__('Yes', 'wordfence')); ?></a> <a href="#" onclick="WFAD.wordfenceSatisfactionChoice('no'); return false;" class="wf-btn wf-btn-default wf-btn-sm" role="button"><?php printf(__('No', 'wordfence')); ?></a></p>
|
||||
<div id="wordfenceSatisfactionPrompt-yes" style="display: none;">
|
||||
<p><?php printf(__('Please consider leaving us a 5-star review on wordpress.org. Your review helps other members of the WordPress community find plugins that fit their needs.', 'wordfence')); ?></p>
|
||||
<p><a href="https://wordpress.org/support/plugin/wordfence/reviews/" class="wf-btn wf-btn-default wf-btn-sm" role="button" target="_blank" rel="noopener noreferrer"><?php printf(__('Leave Review', 'wordfence')); ?></a></p>
|
||||
</div>
|
||||
<div id="wordfenceSatisfactionPrompt-no" style="display: none;">
|
||||
<p><?php printf(__('What can we do to improve Wordfence Security?', 'wordfence')); ?></p>
|
||||
<p><textarea rows="6" cols="50" id="wordfenceSatisfactionPrompt-feedback"></textarea></p>
|
||||
<p><a href="#" onclick="WFAD.wordfenceSatisfactionChoice('feedback'); return false;" class="wf-btn wf-btn-default wf-btn-sm" role="button" target="_blank" rel="noopener noreferrer"><?php printf(__('Submit Feedback', 'wordfence')); ?></a> <a href="#" onclick="WFAD.wordfenceSatisfactionChoice('dismiss'); return false;" class="wf-btn wf-btn-default wf-btn-sm" role="button"><?php printf(__('Dismiss', 'wordfence')); ?></a></p>
|
||||
</div>
|
||||
<p id="wordfenceSatisfactionPrompt-complete" style="display: none;"><?php printf(__('Thank you for providing your feedback on Wordfence Security', 'wordfence')); ?></p>
|
||||
<button type="button" class="notice-dismiss" onclick="WFAD.wordfenceSatisfactionChoice('dismiss'); return false;"><span class="screen-reader-text">Dismiss this notice.</span></button>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -886,7 +886,7 @@ class wfUtils {
|
||||
}
|
||||
$skipToNext = false;
|
||||
if ($trustedProxies === null) {
|
||||
$trustedProxies = explode("\n", wfConfig::get('howGetIPs_trusted_proxies', ''));
|
||||
$trustedProxies = self::unifiedTrustedProxies();
|
||||
}
|
||||
foreach(array(',', ' ', "\t") as $char){
|
||||
if(strpos($item, $char) !== false){
|
||||
@@ -944,6 +944,29 @@ class wfUtils {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all trusted proxies, combining both the user-entered ones and those from the selected preset.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function unifiedTrustedProxies() {
|
||||
$trustedProxies = explode("\n", wfConfig::get('howGetIPs_trusted_proxies', ''));
|
||||
|
||||
$preset = wfConfig::get('howGetIPs_trusted_proxy_preset');
|
||||
$presets = wfConfig::getJSON('ipResolutionList', array());
|
||||
if (is_array($presets) && isset($presets[$preset])) {
|
||||
$testIPs = array_merge($presets[$preset]['ipv4'], $presets[$preset]['ipv6']);
|
||||
foreach ($testIPs as $val) {
|
||||
if (strlen($val) > 0) {
|
||||
if (wfUtils::isValidIP($val) || wfUtils::isValidCIDRRange($val)) {
|
||||
$trustedProxies[] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $trustedProxies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ip
|
||||
@@ -3122,6 +3145,52 @@ class wfUtils {
|
||||
return $encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to extract a matched pattern from a string. If $pattern has no matching groups, the entire
|
||||
* matched portion is returned. If it has at least one matching group, the first one is returned (others are
|
||||
* ignored). If there is no match, false is returned.
|
||||
*
|
||||
* @param string $pattern
|
||||
* @param string $subject
|
||||
* @param bool $expandToLine Whether or not to expand the captured value to include the entire line's contents
|
||||
* @return false|string
|
||||
*/
|
||||
public static function pregExtract($pattern, $subject, $expandToLine = false) {
|
||||
if (preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
if (count($matches) > 1) {
|
||||
$start = $matches[1][1];
|
||||
$text = $matches[1][0];
|
||||
$end = $start + strlen($text);
|
||||
}
|
||||
else {
|
||||
$start = $matches[0][1];
|
||||
$text = $matches[0][0];
|
||||
$end = $start + strlen($text);
|
||||
}
|
||||
|
||||
if ($expandToLine) {
|
||||
if (preg_match_all('/[\r\n]/', substr($subject, 0, $start), $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$start = $matches[0][count($matches[0]) - 1][1] + 1;
|
||||
}
|
||||
else {
|
||||
$start = 0;
|
||||
}
|
||||
|
||||
if (preg_match('/[\r\n]/', $subject, $matches, PREG_OFFSET_CAPTURE, $end)) {
|
||||
$end = $matches[0][1];
|
||||
}
|
||||
else {
|
||||
$end = strlen($subject) - 0;
|
||||
}
|
||||
|
||||
$text = substr($subject, $start, $end - $start);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not MySQLi should be used directly when needed. Returns true if there's a valid DB handle,
|
||||
* our database test succeeded, our constant is not set to prevent it, and then either $wpdb indicates it's using
|
||||
|
||||
@@ -179,7 +179,7 @@ class wordfence {
|
||||
wfRateLimit::trimData();
|
||||
|
||||
wfCentral::checkForUnsentSecurityEvents();
|
||||
|
||||
|
||||
wfVersionCheckController::shared()->checkVersionsAndWarn();
|
||||
}
|
||||
private static function keyAlert($msg){
|
||||
@@ -192,11 +192,15 @@ class wordfence {
|
||||
$api = new wfAPI($apiKey, wfUtils::getWPVersion());
|
||||
try {
|
||||
$keyType = wfLicense::KEY_TYPE_FREE;
|
||||
$keyData = $api->call('ping_api_key', array(), array('supportHash' => wfConfig::get('supportHash', ''), 'whitelistHash' => wfConfig::get('whitelistHash', ''), 'tldlistHash' => wfConfig::get('tldlistHash', '')));
|
||||
$keyData = $api->call('ping_api_key', array(), array('supportHash' => wfConfig::get('supportHash', ''), 'whitelistHash' => wfConfig::get('whitelistHash', ''), 'tldlistHash' => wfConfig::get('tldlistHash', ''), 'ipResolutionListHash' => wfConfig::get('ipResolutionListHash', '')));
|
||||
if (isset($keyData['_isPaidKey'])) {
|
||||
$keyType = wfConfig::get('keyType');
|
||||
}
|
||||
|
||||
if (isset($keyData['_feedbackBasis'])) {
|
||||
wfConfig::setBool('satisfactionPromptOverride', $keyData['_feedbackBasis'] > WORDFENCE_FEEDBACK_EPOCH);
|
||||
}
|
||||
|
||||
if(isset($keyData['_isPaidKey']) && $keyData['_isPaidKey']){
|
||||
$keyExpDays = $keyData['_keyExpDays'];
|
||||
$keyIsExpired = $keyData['_expired'];
|
||||
@@ -251,6 +255,10 @@ class wordfence {
|
||||
wfConfig::set('tldlist', $keyData['_tldlist']);
|
||||
wfConfig::set('tldlistHash', $keyData['_tldlistHash']);
|
||||
}
|
||||
if (isset($keyData['_ipResolutionList']) && isset($keyData['_ipResolutionListHash'])) {
|
||||
wfConfig::setJSON('ipResolutionList', $keyData['_ipResolutionList']);
|
||||
wfConfig::set('ipResolutionListHash', $keyData['_ipResolutionListHash']);
|
||||
}
|
||||
if (isset($keyData['scanSchedule']) && is_array($keyData['scanSchedule'])) {
|
||||
wfConfig::set_ser('noc1ScanSchedule', $keyData['scanSchedule']);
|
||||
if (wfScanner::shared()->schedulingMode() == wfScanner::SCAN_SCHEDULING_MODE_AUTOMATIC) {
|
||||
@@ -1080,6 +1088,11 @@ SQL
|
||||
if (wfConfig::get('isPaid') && (wfCredentialsController::hasOld2FARecords() || version_compare(phpversion(), '5.3', '<'))) {
|
||||
wfConfig::set(wfCredentialsController::ALLOW_LEGACY_2FA_OPTION, true);
|
||||
}
|
||||
|
||||
//Record the installation timestamp if activating the plugin for the first time
|
||||
if (get_option('wordfenceActivated') != 1 && wfConfig::get('satisfactionPromptInstallDate') == 0 && empty(wfConfig::get('apiKey'))) {
|
||||
wfConfig::set('satisfactionPromptInstallDate', time());
|
||||
}
|
||||
|
||||
//Check the How does Wordfence get IPs setting
|
||||
wfUtils::requestDetectProxyCallback();
|
||||
@@ -2168,6 +2181,7 @@ SQL
|
||||
}
|
||||
hash_update($scontext, $data);
|
||||
}
|
||||
|
||||
fclose($sp);
|
||||
if ($scontext !== false) {
|
||||
$shash = hash_final($scontext, false);
|
||||
@@ -2184,6 +2198,7 @@ SQL
|
||||
}
|
||||
hash_update($dcontext, $data);
|
||||
}
|
||||
|
||||
fclose($dp);
|
||||
if ($scontext !== false) {
|
||||
$dhash = hash_final($dcontext, false);
|
||||
@@ -2292,7 +2307,7 @@ SQL
|
||||
'whitelistedIPs' => (string) wfConfig::get('whitelisted'),
|
||||
'whitelistedServiceIPs' => @json_encode(wfUtils::whitelistedServiceIPs()),
|
||||
'howGetIPs' => (string) wfConfig::get('howGetIPs'),
|
||||
'howGetIPs_trusted_proxies' => wfConfig::get('howGetIPs_trusted_proxies', ''),
|
||||
'howGetIPs_trusted_proxies_unified' => implode("\n", wfUtils::unifiedTrustedProxies()),
|
||||
'detectProxyRecommendation' => (string) wfConfig::get('detectProxyRecommendation'),
|
||||
'other_WFNet' => !!wfConfig::get('other_WFNet', true),
|
||||
'pluginABSPATH' => ABSPATH,
|
||||
@@ -3232,10 +3247,9 @@ SQL
|
||||
$threshold = wfConfig::get('lastBruteForceDataSendTime', 0);;
|
||||
|
||||
$wfdb = new wfDB();
|
||||
global $wpdb;
|
||||
$table_wfHits = wfDB::networkTable('wfHits');
|
||||
$rawBlocks = $wfdb->querySelect("SELECT SQL_CALC_FOUND_ROWS IP, ctime, actionData FROM {$table_wfHits} WHERE ctime > %f AND action = 'blocked:wfsnrepeat' ORDER BY ctime ASC LIMIT 100", sprintf('%.6f', $threshold));
|
||||
$totalRows = $wpdb->get_var('SELECT FOUND_ROWS()');
|
||||
$rawBlocks = $wfdb->querySelect("SELECT IP, ctime, actionData FROM {$table_wfHits} WHERE ctime > %f AND action = 'blocked:wfsnrepeat' ORDER BY ctime ASC LIMIT 100", sprintf('%.6f', $threshold));
|
||||
$totalRows = $wfdb->querySingle("SELECT COUNT(*) FROM {$table_wfHits} WHERE ctime > %f AND action = 'blocked:wfsnrepeat'", sprintf('%.6f', $threshold));
|
||||
$ipCounts = array();
|
||||
$maxctime = 0;
|
||||
foreach ($rawBlocks as $record) {
|
||||
@@ -4076,6 +4090,7 @@ SQL
|
||||
if (isset($_POST['page'])) {
|
||||
$page = $_POST['page'];
|
||||
}
|
||||
|
||||
|
||||
$keys = array(wfOnboardingController::TOUR_DASHBOARD, wfOnboardingController::TOUR_FIREWALL, wfOnboardingController::TOUR_SCAN, wfOnboardingController::TOUR_BLOCKING, wfOnboardingController::TOUR_LIVE_TRAFFIC, wfOnboardingController::TOUR_LOGIN_SECURITY);
|
||||
if (in_array($page, $keys)) {
|
||||
@@ -4126,6 +4141,16 @@ SQL
|
||||
}
|
||||
return array('ok' => 1);
|
||||
}
|
||||
public static function ajax_wordfenceSatisfactionChoice_callback() {
|
||||
wfConfig::set('satisfactionPromptDismissed', time());
|
||||
$choice = $_POST['choice'];
|
||||
if ($choice == 'feedback' && isset($_POST['feedback']) && !empty($_POST['feedback'])) {
|
||||
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
||||
$result = $api->call('plugin_feedback', array(), array('feedback' => $_POST['feedback']));
|
||||
}
|
||||
//else -- no additional action for yes/no
|
||||
return array('ok' => 1);
|
||||
}
|
||||
public static function ajax_dismissAdminNotice_callback() {
|
||||
if (isset($_POST['id'])) {
|
||||
wfAdminNoticeQueue::removeAdminNotice($_POST['id']);
|
||||
@@ -4658,9 +4683,22 @@ SQL
|
||||
}
|
||||
$trustedProxies = $validIPs;
|
||||
|
||||
$preset = $_POST['howGetIPs_trusted_proxy_preset'];
|
||||
$presets = wfConfig::getJSON('ipResolutionList', array());
|
||||
if (is_array($presets) && isset($presets[$preset])) {
|
||||
$testIPs = array_merge($presets[$preset]['ipv4'], $presets[$preset]['ipv6']);
|
||||
foreach ($testIPs as $val) {
|
||||
if (strlen($val) > 0) {
|
||||
if (wfUtils::isValidIP($val) || wfUtils::isValidCIDRRange($val)) {
|
||||
$trustedProxies[] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ipAll = wfUtils::getIPPreview($howGet, $trustedProxies);
|
||||
$ip = wfUtils::getIPForField($howGet, $trustedProxies);
|
||||
return array('ok' => 1, 'ip' => $ip, 'ipAll' => $ipAll);
|
||||
return array('ok' => 1, 'ip' => $ip, 'ipAll' => $ipAll, 'resolvedProxies' => $trustedProxies);
|
||||
}
|
||||
|
||||
public static function ajax_hideFileHtaccess_callback(){
|
||||
@@ -6081,6 +6119,8 @@ HTML;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (wfConfig::get('touppBypassNextCheck')) {
|
||||
wfConfig::set('touppBypassNextCheck', 0);
|
||||
wfConfig::set('touppPromptNeeded', 0);
|
||||
@@ -6092,7 +6132,7 @@ HTML;
|
||||
'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues',
|
||||
'avatarLookup', 'reverseLookup', 'unlockOutIP', 'unblockRange', 'whois', 'recentTraffic', 'unblockIP',
|
||||
'blockIP', 'permBlockIP', 'loadStaticPanel', 'updateIPPreview', 'downloadHtaccess', 'downloadLogFile', 'checkHtaccess',
|
||||
'updateConfig', 'autoUpdateChoice', 'misconfiguredHowGetIPsChoice', 'switchLiveTrafficSecurityOnlyChoice', 'dismissAdminNotice',
|
||||
'updateConfig', 'autoUpdateChoice', 'misconfiguredHowGetIPsChoice', 'switchLiveTrafficSecurityOnlyChoice', 'dismissAdminNotice', 'wordfenceSatisfactionChoice',
|
||||
'killScan', 'saveCountryBlocking', 'tourClosed',
|
||||
'downgradeLicense', 'addTwoFactor', 'twoFacActivate', 'twoFacDel',
|
||||
'loadTwoFactor', 'sendTestEmail',
|
||||
@@ -6153,7 +6193,7 @@ HTML;
|
||||
wp_enqueue_style('wordfence-global-style', wfUtils::getBaseURL() . wfUtils::versionedAsset('css/wf-global.css'), '', WORDFENCE_VERSION);
|
||||
self::setupAdminVars();
|
||||
}
|
||||
|
||||
|
||||
if (is_admin()) { //Back end only
|
||||
if (wfOnboardingController::shouldShowAnyAttempt()) {
|
||||
wp_enqueue_script('wordfenceOnboardingjs', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/wfonboarding.js'), array('jquery', 'wordfenceAdminExtjs'), WORDFENCE_VERSION);
|
||||
@@ -6807,6 +6847,15 @@ HTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$warningAdded && wfSupportController::shouldShowSatisfactionPrompt()) {
|
||||
if (is_multisite()) {
|
||||
add_action('network_admin_notices', 'wfSupportController::satisfactionPromptNotice');
|
||||
}
|
||||
else {
|
||||
add_action('admin_notices', 'wfSupportController::satisfactionPromptNotice');
|
||||
}
|
||||
}
|
||||
|
||||
if (self::isWordfenceAdminPage()) {
|
||||
$dashboardExtra = '';
|
||||
@@ -8699,13 +8748,25 @@ SQL;
|
||||
$entry = bin2hex($packed);
|
||||
}
|
||||
$wafAlertWhitelist = array_filter($wafAlertWhitelist);
|
||||
$attackData = $wpdb->get_results($wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS * FROM {$table_wfHits}
|
||||
WHERE action = 'blocked:waf' " .
|
||||
(count($wafAlertWhitelist) ? "AND HEX(IP) NOT IN (" . implode(", ", array_fill(0, count($wafAlertWhitelist), '%s')) . ")" : "")
|
||||
. "AND attackLogTime > %f
|
||||
ORDER BY attackLogTime DESC
|
||||
LIMIT 10", array_merge($wafAlertWhitelist, array(sprintf('%.6f', $cutoffTime)))));
|
||||
$attackCount = $wpdb->get_var('SELECT FOUND_ROWS()');
|
||||
$attackDataQuery = $wpdb->prepare(
|
||||
"SELECT * FROM {$table_wfHits}
|
||||
WHERE action = 'blocked:waf' " .
|
||||
(count($wafAlertWhitelist) ? "AND HEX(IP) NOT IN (" . implode(", ", array_fill(0, count($wafAlertWhitelist), '%s')) . ")" : "")
|
||||
. " AND attackLogTime > %f
|
||||
ORDER BY attackLogTime DESC
|
||||
LIMIT 10",
|
||||
array_merge($wafAlertWhitelist, array(sprintf('%.6f', $cutoffTime))));
|
||||
$attackDataCountQuery = str_replace(
|
||||
array(
|
||||
"SELECT * FROM",
|
||||
"ORDER BY attackLogTime DESC",
|
||||
"LIMIT 10",
|
||||
),
|
||||
array( "SELECT COUNT(*) FROM", "", "" ), $attackDataQuery
|
||||
);
|
||||
$attackData = $wpdb->get_results($attackDataQuery);
|
||||
$attackCount = $wpdb->get_var($attackDataCountQuery);
|
||||
unset( $attackDataQuery, $attackDataCountQuery );
|
||||
$threshold = (int) wfConfig::get('wafAlertThreshold');
|
||||
if ($threshold < 1) {
|
||||
$threshold = 100;
|
||||
@@ -8803,21 +8864,38 @@ SQL;
|
||||
$lastSendTime = wfConfig::get('lastAttackDataSendTime');
|
||||
$lastSendId = wfConfig::get('lastAttackDataSendId');
|
||||
if($lastSendId===false){
|
||||
$query=$wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS * FROM {$table_wfHits}
|
||||
$query=$wpdb->prepare("SELECT * FROM {$table_wfHits}
|
||||
WHERE action in ('blocked:waf', 'learned:waf', 'logged:waf', 'blocked:waf-always')
|
||||
AND attackLogTime > %f
|
||||
LIMIT %d", sprintf('%.6f', $lastSendTime), $limit);
|
||||
|
||||
$count_query = str_replace(
|
||||
array(
|
||||
"SELECT * FROM",
|
||||
"LIMIT " . $limit,
|
||||
),
|
||||
array( "SELECT COUNT(*) FROM", "" ), $query
|
||||
);
|
||||
}
|
||||
else{
|
||||
$query=$wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS * FROM {$table_wfHits}
|
||||
$query=$wpdb->prepare("SELECT * FROM {$table_wfHits}
|
||||
WHERE action in ('blocked:waf', 'learned:waf', 'logged:waf', 'blocked:waf-always')
|
||||
AND id > %d
|
||||
ORDER BY id LIMIT %d", $lastSendId, $limit);
|
||||
|
||||
$count_query = str_replace(
|
||||
array(
|
||||
"SELECT * FROM",
|
||||
"ORDER BY id LIMIT " . $limit,
|
||||
),
|
||||
array( "SELECT COUNT(*) FROM", "" ), $query
|
||||
);
|
||||
}
|
||||
|
||||
$params[]=$limit;
|
||||
$attackData = $wpdb->get_results($query);
|
||||
$totalRows = $wpdb->get_var('SELECT FOUND_ROWS()');
|
||||
|
||||
$totalRows = $wpdb->get_var($count_query);
|
||||
|
||||
if ($attackData) { // Build JSON to send
|
||||
$dataToSend = array();
|
||||
$attackDataToUpdate = array();
|
||||
@@ -9909,7 +9987,7 @@ class wfWAFAutoPrependHelper {
|
||||
|
||||
public function getFilesNeededForBackup() {
|
||||
$backups = array();
|
||||
$htaccess = $this->getHtaccessPath();
|
||||
$htaccess = wfWAFAutoPrependHelper::getHtaccessPath();
|
||||
switch ($this->getServerConfig()) {
|
||||
case 'apache-mod_php':
|
||||
case 'apache-suphp':
|
||||
@@ -9921,7 +9999,7 @@ class wfWAFAutoPrependHelper {
|
||||
break;
|
||||
}
|
||||
if ($userIni = ini_get('user_ini.filename')) {
|
||||
$userIniPath = $this->getUserIniPath();
|
||||
$userIniPath = wfWAFAutoPrependHelper::getUserIniPath();
|
||||
switch ($this->getServerConfig()) {
|
||||
case 'cgi':
|
||||
case 'apache-suphp':
|
||||
@@ -9979,10 +10057,10 @@ class wfWAFAutoPrependHelper {
|
||||
|
||||
$serverConfig = $this->getServerConfig();
|
||||
|
||||
$htaccessPath = $this->getHtaccessPath();
|
||||
$htaccessPath = wfWAFAutoPrependHelper::getHtaccessPath();
|
||||
$homePath = dirname($htaccessPath);
|
||||
|
||||
$userIniPath = $this->getUserIniPath();
|
||||
$userIniPath = wfWAFAutoPrependHelper::getUserIniPath();
|
||||
$userIni = ini_get('user_ini.filename');
|
||||
|
||||
$userIniHtaccessDirectives = '';
|
||||
@@ -10122,9 +10200,9 @@ auto_prepend_file = '%s'
|
||||
public function performIniRemoval($wp_filesystem) {
|
||||
$serverConfig = $this->getServerConfig();
|
||||
|
||||
$htaccessPath = $this->getHtaccessPath();
|
||||
$htaccessPath = wfWAFAutoPrependHelper::getHtaccessPath();
|
||||
|
||||
$userIniPath = $this->getUserIniPath();
|
||||
$userIniPath = wfWAFAutoPrependHelper::getUserIniPath();
|
||||
$userIni = ini_get('user_ini.filename');
|
||||
|
||||
// Modify .htaccess
|
||||
@@ -10174,12 +10252,12 @@ auto_prepend_file = '%s'
|
||||
throw new wfWAFAutoPrependHelperException(__('We were unable to remove the <code>wordfence-waf.php</code> file in the root of the WordPress installation. It\'s possible WordPress cannot remove the <code>wordfence-waf.php</code> file because of file permissions. Please verify the permissions are correct and retry the removal.', 'wordfence'));
|
||||
}
|
||||
}
|
||||
|
||||
public function getHtaccessPath() {
|
||||
|
||||
public static function getHtaccessPath() {
|
||||
return wfUtils::getHomePath() . '.htaccess';
|
||||
}
|
||||
|
||||
public function getUserIniPath() {
|
||||
|
||||
public static function getUserIniPath() {
|
||||
$userIni = ini_get('user_ini.filename');
|
||||
if ($userIni) {
|
||||
return wfUtils::getHomePath() . $userIni;
|
||||
@@ -10187,6 +10265,36 @@ auto_prepend_file = '%s'
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the WAF section from the .htaccess content and returns it (inclusive of the section markers). If not
|
||||
* present, returns false.
|
||||
*
|
||||
* @param string $htaccessContent
|
||||
* @return false|string
|
||||
*/
|
||||
public static function getHtaccessSectionContent($htaccessContent) {
|
||||
$regex = '/# Wordfence WAF.*?# END Wordfence WAF/is';
|
||||
if (preg_match($regex, $htaccessContent, $matches)) {
|
||||
return $matches[0];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the WAF section from the .user.ini content and returns it (inclusive of the section markers). If not
|
||||
* present, returns false.
|
||||
*
|
||||
* @param string $userIniContent
|
||||
* @return false|string
|
||||
*/
|
||||
public static function getUserIniSectionContent($userIniContent) {
|
||||
$regex = '/; Wordfence WAF.*?; END Wordfence WAF/is';
|
||||
if (preg_match($regex, $userIniContent, $matches)) {
|
||||
return $matches[0];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function usesUserIni() {
|
||||
$userIni = ini_get('user_ini.filename');
|
||||
if (!$userIni) {
|
||||
@@ -10207,8 +10315,8 @@ auto_prepend_file = '%s'
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
$htaccessPath = $this->getHtaccessPath();
|
||||
$userIniPath = $this->getUserIniPath();
|
||||
$htaccessPath = wfWAFAutoPrependHelper::getHtaccessPath();
|
||||
$userIniPath = wfWAFAutoPrependHelper::getUserIniPath();
|
||||
|
||||
$adminURL = admin_url('/');
|
||||
$allow_relaxed_file_ownership = true;
|
||||
@@ -10267,4 +10375,4 @@ auto_prepend_file = '%s'
|
||||
}
|
||||
|
||||
class wfWAFAutoPrependHelperException extends Exception {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
define('WORDFENCE_EPOCH', 1312156800);
|
||||
define('WORDFENCE_FEEDBACK_EPOCH', 1704213261);
|
||||
define('WORDFENCE_API_VERSION', '2.26');
|
||||
define('WORDFENCE_API_URL_SEC', 'https://noc1.wordfence.com/');
|
||||
define('WORDFENCE_API_URL_NONSEC', 'http://noc1.wordfence.com/');
|
||||
|
||||
@@ -110,6 +110,10 @@ class wordfenceURLHoover {
|
||||
public function captureURL($matches) {
|
||||
$id = $this->currentHooverID;
|
||||
$url = 'http:' . $matches[0];
|
||||
if (!filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$components = parse_url($url);
|
||||
if (preg_match('/\.(xn--(?:[a-z0-9-]*)[a-z0-9]+|[a-z\xa1-\xff0-9]{2,})$/i', $components['host'], $tld)) {
|
||||
$tld = strtolower($tld[1]);
|
||||
@@ -126,9 +130,6 @@ class wordfenceURLHoover {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_foundSome++;
|
||||
|
||||
|
||||
+4
@@ -341,6 +341,10 @@ END
|
||||
'Send' => __('Send', 'wordfence'),
|
||||
'An error was encountered while trying to send the message. Please try again.' => __('An error was encountered while trying to send the message. Please try again.', 'wordfence'),
|
||||
'<strong>ERROR</strong>: An error was encountered while trying to send the message. Please try again.' => wp_kses(__('<strong>ERROR</strong>: An error was encountered while trying to send the message. Please try again.', 'wordfence'), array('strong' => array())),
|
||||
'Login failed with status code 403. Please contact the site administrator.' => __('Login failed with status code 403. Please contact the site administrator.', 'wordfence'),
|
||||
'<strong>ERROR</strong>: Login failed with status code 403. Please contact the site administrator.' => wp_kses(__('<strong>ERROR</strong>: Login failed with status code 403. Please contact the site administrator.', 'wordfence'), array('strong' => array())),
|
||||
'Login failed with status code 503. Please contact the site administrator.' => __('Login failed with status code 503. Please contact the site administrator.', 'wordfence'),
|
||||
'<strong>ERROR</strong>: Login failed with status code 503. Please contact the site administrator.' => wp_kses(__('<strong>ERROR</strong>: Login failed with status code 503. Please contact the site administrator.', 'wordfence'), array('strong' => array())),
|
||||
'Wordfence 2FA Code' => __('Wordfence 2FA Code', 'wordfence'),
|
||||
'Remember for 30 days' => __('Remember for 30 days', 'wordfence'),
|
||||
'Log In' => __('Log In', 'wordfence'),
|
||||
|
||||
+13
-1
@@ -423,7 +423,19 @@
|
||||
},
|
||||
error: function(err) {
|
||||
if (err.status == 503 || err.status == 403) {
|
||||
window.location.reload(true);
|
||||
if ($('.woocommerce').length > 0) {
|
||||
if (err.status == 503) {
|
||||
showLoginMessage(__('<strong>ERROR</strong>: Login failed with status code 503. Please contact the site administrator.'), 'error');
|
||||
}
|
||||
else if (err.status == 403) {
|
||||
showLoginMessage(__('<strong>ERROR</strong>: Login failed with status code 403. Please contact the site administrator.'), 'error');
|
||||
}
|
||||
blocker.unblock();
|
||||
}
|
||||
else {
|
||||
window.location.reload(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
showLoginMessage(__('<strong>ERROR</strong>: An error was encountered while trying to authenticate. Please try again.'), 'error');
|
||||
@@ -26,8 +26,8 @@ if ($wfCoreActive && !(isset($wfCoreLoading) && $wfCoreLoading)) {
|
||||
else {
|
||||
define('WORDFENCE_LS_FROM_CORE', ($wfCoreActive && isset($wfCoreLoading) && $wfCoreLoading));
|
||||
|
||||
define('WORDFENCE_LS_VERSION', '1.1.7');
|
||||
define('WORDFENCE_LS_BUILD_NUMBER', '1699289814');
|
||||
define('WORDFENCE_LS_VERSION', '1.1.8');
|
||||
define('WORDFENCE_LS_BUILD_NUMBER', '1704213472');
|
||||
|
||||
define('WORDFENCE_LS_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Tags: security, waf, malware, 2fa, two factor, login security, firewall, brute f
|
||||
Requires at least: 3.9
|
||||
Requires PHP: 5.5
|
||||
Tested up to: 6.4
|
||||
Stable tag: 7.10.7
|
||||
Stable tag: 7.11.1
|
||||
License: GPLv3
|
||||
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
@@ -189,6 +189,25 @@ Secure your website with Wordfence.
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 7.11.1 - January 2, 2024 =
|
||||
* Improvement: Added ".env" to the files checked for "Scan for publicly accessible configuration, backup, or log files"
|
||||
* Improvement: Provided better descriptive text for the option "Block IPs who send POST requests with blank User-Agent and Referer"
|
||||
* Improvement: The diagnostics page now displays the contents of any `auto_prepend_file` .htaccess/.user.ini block for troubleshooting
|
||||
* Fix: Fixed an issue where a login lockout on a WooCommerce login form could fail silently
|
||||
* Fix: The scan result for abandoned plugins no longer states it has been removed from wordpress.org if it is still listed
|
||||
* Fix: Addressed an exception parsing date information in non-repo plugins that have a bad `last_updated` value
|
||||
* Fix: The URL scanner no longer generates a log warning when matching a potential URL fragment that ends up not being a valid URL
|
||||
|
||||
= 7.11.0 - November 28, 2023 =
|
||||
* Improvement: Added new functionality for trusted proxy presets to support proxies such as Amazon CloudFront, Ezoic, and Quic.cloud
|
||||
* Improvement: WAF rule and malware signature updates are now signed with SHA-256 as well for hosts that no longer build SHA1 support
|
||||
* Improvement: Updated the bundled trusted CA certificates
|
||||
* Change: The WAF will no longer attempt to fetch rule or blocklist updates when run via WP-CLI
|
||||
* Fix: Removed uses of SQL_CALC_FOUND_ROWS, which is deprecated as of MySQL 8.0.17
|
||||
* Fix: Fixed an issue where final scan summary counts in some instances were not sent to Central
|
||||
* Fix: Fixed a deprecation notice for get_class in PHP 8.3.0
|
||||
* Fix: Corrected an output error in the connectivity section of Diagnostics in text mode
|
||||
|
||||
= 7.10.7 - November 6, 2023 =
|
||||
* Fix: Compatibility fix for WordPress 6.4 on the login page styling
|
||||
|
||||
|
||||
+1082
-1138
File diff suppressed because it is too large
Load Diff
+1
@@ -572,6 +572,7 @@ class wfWAFStorageMySQL implements wfWAFStorageInterface {
|
||||
'whitelistedIPs',
|
||||
'howGetIPs',
|
||||
'howGetIPs_trusted_proxies',
|
||||
'howGetIPs_trusted_proxies_unified',
|
||||
'other_WFNet',
|
||||
'pluginABSPATH',
|
||||
'serverIPs',
|
||||
|
||||
@@ -304,12 +304,12 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
||||
|
||||
// Check if this is signed request and update ruleset.
|
||||
|
||||
$ping = $this->getRequest()->getBody('ping');
|
||||
$ping = $this->getRequest()->getBody('ping256');
|
||||
$pingResponse = $this->getRequest()->getBody('ping_response');
|
||||
|
||||
if ($ping && $pingResponse &&
|
||||
wfWAFUtils::hash_equals($ping, sha1($this->getStorageEngine()->getConfig('apiKey', null, 'synced'))) &&
|
||||
$this->verifySignedRequest($this->getRequest()->getBody('signature'), $this->getStorageEngine()->getConfig('apiKey', null, 'synced'))
|
||||
$this->verifyPing($ping) &&
|
||||
$this->verifySignedRequest($this->getRequest()->getBody('signature256'), $this->getStorageEngine()->getConfig('apiKey', null, 'synced'))
|
||||
) {
|
||||
// $this->updateRuleSet(base64_decode($this->getRequest()->body('ping')));
|
||||
$event = new wfWAFCronFetchRulesEvent(time() - 2);
|
||||
@@ -318,7 +318,7 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
||||
|
||||
header('Content-type: text/plain');
|
||||
$pingResponse = preg_replace('/[a-zA-Z0-9]/', '', $this->getRequest()->getBody('ping_response'));
|
||||
exit('Success: ' . sha1($this->getStorageEngine()->getConfig('apiKey', null, 'synced') . $pingResponse));
|
||||
exit('Success: ' . hash('sha256', $this->getStorageEngine()->getConfig('apiKey', null, 'synced') . $pingResponse));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,6 +469,8 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
||||
}
|
||||
|
||||
protected function runMigrations() {
|
||||
if (!wfWAFStorageFile::allowFileWriting()) { return false; }
|
||||
|
||||
$storageEngine = $this->getStorageEngine();
|
||||
$currentVersion = $storageEngine->getConfig('version');
|
||||
if (wfWAFUtils::isVersionBelow(WFWAF_VERSION, $currentVersion)) {
|
||||
@@ -534,6 +536,7 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
||||
'whitelistedIPs' => 'synced',
|
||||
'howGetIPs' => 'synced',
|
||||
'howGetIPs_trusted_proxies' => 'synced',
|
||||
'howGetIPs_trusted_proxies_unified' => 'synced',
|
||||
'pluginABSPATH' => 'synced',
|
||||
'other_WFNet' => 'synced',
|
||||
'serverIPs' => 'synced',
|
||||
@@ -621,17 +624,22 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
||||
public function hasOpenSSL() {
|
||||
return function_exists('openssl_verify');
|
||||
}
|
||||
|
||||
public function verifyPing($ping, $algorithm = 'sha256') {
|
||||
$hash = hash($algorithm, $this->getStorageEngine()->getConfig('apiKey', null, 'synced'));
|
||||
return wfWAFUtils::hash_equals($ping, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $signature
|
||||
* @param string $data
|
||||
* @return bool
|
||||
*/
|
||||
public function verifySignedRequest($signature, $data) {
|
||||
public function verifySignedRequest($signature, $data, $algorithm = OPENSSL_ALGO_SHA256) {
|
||||
if (!$this->hasOpenSSL()) {
|
||||
return false;
|
||||
}
|
||||
$valid = openssl_verify($data, $signature, $this->getPublicKey(), OPENSSL_ALGO_SHA1);
|
||||
$valid = openssl_verify($data, $signature, $this->getPublicKey(), $algorithm);
|
||||
return $valid === 1;
|
||||
}
|
||||
|
||||
@@ -1937,13 +1945,13 @@ class wfWAFCronFetchRulesEvent extends wfWAFCronEvent {
|
||||
if (is_array($jsonData)) {
|
||||
|
||||
if ($waf->hasOpenSSL() &&
|
||||
isset($jsonData['data']['signature']) &&
|
||||
isset($jsonData['data']['signature256']) &&
|
||||
isset($jsonData['data']['rules']) &&
|
||||
$waf->verifySignedRequest(base64_decode($jsonData['data']['signature']), $jsonData['data']['rules'])
|
||||
$waf->verifySignedRequest(base64_decode($jsonData['data']['signature256']), $jsonData['data']['rules'])
|
||||
) {
|
||||
$waf->updateRuleSet(base64_decode($jsonData['data']['rules']),
|
||||
isset($jsonData['data']['timestamp']) ? $jsonData['data']['timestamp'] : true);
|
||||
$waf->getStorageEngine()->setConfig('lastRuleHash', $jsonData['data']['signature'], 'transient');
|
||||
$waf->getStorageEngine()->setConfig('lastRuleHash', $jsonData['data']['signature256'], 'transient');
|
||||
if (array_key_exists('premiumCount', $jsonData['data'])) {
|
||||
$waf->getStorageEngine()->setConfig('premiumCount', $jsonData['data']['premiumCount'], 'transient');
|
||||
}
|
||||
@@ -1992,25 +2000,25 @@ class wfWAFCronFetchRulesEvent extends wfWAFCronEvent {
|
||||
$jsonData = wfWAFUtils::json_decode($this->response->getBody(), true);
|
||||
if (is_array($jsonData)) {
|
||||
if ($waf->hasOpenSSL() &&
|
||||
isset($jsonData['data']['signature']) &&
|
||||
isset($jsonData['data']['signature256']) &&
|
||||
isset($jsonData['data']['signatures']) &&
|
||||
$waf->verifySignedRequest(base64_decode($jsonData['data']['signature']), $jsonData['data']['signatures'])
|
||||
$waf->verifySignedRequest(base64_decode($jsonData['data']['signature256']), $jsonData['data']['signatures'])
|
||||
) {
|
||||
$waf->setMalwareSignatures(wfWAFUtils::json_decode(base64_decode($jsonData['data']['signatures'])),
|
||||
isset($jsonData['data']['timestamp']) ? $jsonData['data']['timestamp'] : true);
|
||||
$waf->getStorageEngine()->setConfig('lastMalwareHash', $jsonData['data']['signature'], 'transient');
|
||||
$waf->getStorageEngine()->setConfig('lastMalwareHash', $jsonData['data']['signature256'], 'transient');
|
||||
if (array_key_exists('premiumCount', $jsonData['data'])) {
|
||||
$waf->getStorageEngine()->setConfig('signaturePremiumCount', $jsonData['data']['premiumCount'], 'transient');
|
||||
}
|
||||
|
||||
if (array_key_exists('commonStringsSignature', $jsonData['data']) &&
|
||||
if (array_key_exists('commonStringsSignature256', $jsonData['data']) &&
|
||||
array_key_exists('commonStrings', $jsonData['data']) &&
|
||||
array_key_exists('signatureIndexes', $jsonData['data']) &&
|
||||
$waf->verifySignedRequest(base64_decode($jsonData['data']['commonStringsSignature']), $jsonData['data']['commonStrings'] . $jsonData['data']['signatureIndexes'])
|
||||
$waf->verifySignedRequest(base64_decode($jsonData['data']['commonStringsSignature256']), $jsonData['data']['commonStrings'] . $jsonData['data']['signatureIndexes'])
|
||||
) {
|
||||
$waf->setMalwareSignatureCommonStrings(wfWAFUtils::json_decode(base64_decode($jsonData['data']['commonStrings'])), wfWAFUtils::json_decode(base64_decode($jsonData['data']['signatureIndexes'])));
|
||||
|
||||
$waf->getStorageEngine()->setConfig('lastMalwareHashCommonStrings', $jsonData['data']['commonStringsSignature'], 'transient');
|
||||
$waf->getStorageEngine()->setConfig('lastMalwareHashCommonStrings', $jsonData['data']['commonStringsSignature256'], 'transient');
|
||||
}
|
||||
|
||||
} else if (!$waf->hasOpenSSL() &&
|
||||
|
||||
@@ -58,12 +58,42 @@ $selectOptions = array(
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="howGetIPs-trusted-proxy-preset">
|
||||
<ul id="wf-option-howGetIPs-trusted-proxy-preset" class="wf-option wf-option-select" data-text-option="howGetIPs_trusted_proxy_preset" data-original-text-value="<?php echo esc_attr(wfConfig::get('howGetIPs_trusted_proxy_preset')); ?>">
|
||||
<li class="wf-option-spacer"></li>
|
||||
<li class="wf-option-content">
|
||||
<ul>
|
||||
<li class="wf-option-title">
|
||||
<ul class="wf-flex-vertical wf-flex-align-left">
|
||||
<li><span id="wf-option-howGetIPs-trusted-proxy-preset-label"><?php esc_html_e('Trusted Proxy Preset', 'wordfence'); ?></span></li>
|
||||
<li class="wf-option-subtitle"><?php esc_html_e('In addition to the above list, the IPs (or CIDR ranges) in the selected preset will be ignored when determining the requesting IP via the X-Forwarded-For HTTP header.', 'wordfence'); ?></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="wf-option-select">
|
||||
<?php
|
||||
$presets = wfConfig::getJSON('ipResolutionList', array());
|
||||
if (!is_array($presets)) {
|
||||
$presets = array();
|
||||
}
|
||||
$keys = array_keys($presets); asort($keys);
|
||||
?>
|
||||
<select<?php echo (!empty($presets) ? '' : ' disabled'); ?> aria-labelledby="wf-option-howGetIPs-trusted-proxy-preset-label">
|
||||
<option class="wf-option-select-option" value=""<?php if (!in_array(wfConfig::get('howGetIPs_trusted_proxy_preset'), $keys)) { echo ' selected'; } ?>><?php esc_html_e('None', 'wordfence'); ?></option>
|
||||
<?php foreach ($keys as $k): ?>
|
||||
<option class="wf-option-select-option" value="<?php echo esc_attr($k); ?>"<?php if ($k == wfConfig::get('howGetIPs_trusted_proxy_preset')) { echo ' selected'; } ?>><?php echo esc_html($presets[$k]['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<script type="application/javascript">
|
||||
(function($) {
|
||||
$(function() {
|
||||
var updateIPPreview = function() {
|
||||
WFAD.updateIPPreview({howGetIPs: $('input[name="wf-howgetIPs"]:checked').val(), 'howGetIPs_trusted_proxies': $('#howGetIPs-trusted-proxies textarea').val()}, function(ret) {
|
||||
WFAD.updateIPPreview({howGetIPs: $('input[name="wf-howgetIPs"]:checked').val(), 'howGetIPs_trusted_proxies': $('#howGetIPs-trusted-proxies textarea').val(), 'howGetIPs_trusted_proxy_preset': $('#howGetIPs-trusted-proxy-preset select').val()}, function(ret) {
|
||||
if (ret && ret.ok) {
|
||||
$('#howGetIPs-preview-all').html(ret.ipAll);
|
||||
$('#howGetIPs-preview-single').html(ret.ip);
|
||||
@@ -116,6 +146,29 @@ $selectOptions = array(
|
||||
}, 4);
|
||||
});
|
||||
|
||||
$('#howGetIPs-trusted-proxy-preset').on('change', function() {
|
||||
var e = this;
|
||||
|
||||
setTimeout(function() {
|
||||
clearTimeout(coalescingUpdateTimer);
|
||||
coalescingUpdateTimer = setTimeout(updateIPPreview, 1000);
|
||||
|
||||
var optionElement = $(e).find('.wf-option.wf-option-select');
|
||||
var option = optionElement.data('textOption');
|
||||
var value = $(e).find('select').val();
|
||||
|
||||
var originalValue = optionElement.data('originalTextValue');
|
||||
if (originalValue == value) {
|
||||
delete WFAD.pendingChanges[option];
|
||||
}
|
||||
else {
|
||||
WFAD.pendingChanges[option] = value;
|
||||
}
|
||||
|
||||
WFAD.updatePendingChanges();
|
||||
}, 4);
|
||||
});
|
||||
|
||||
$(window).on('wfOptionsReset', function() {
|
||||
$('input[name="wf-howgetIPs"]').each(function() {
|
||||
var optionElement = $(this).closest('.wf-option.wf-option-howgetips');
|
||||
@@ -155,6 +208,12 @@ $selectOptions = array(
|
||||
$('#howGetIPs-trusted-proxies').removeClass('wf-active');
|
||||
}
|
||||
});
|
||||
|
||||
$('#howGetIPs-trusted-proxy-preset').slideUp({
|
||||
always: function() {
|
||||
$('#howGetIPs-trusted-proxy-preset').removeClass('wf-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
$(this).parent().slideUp();
|
||||
@@ -163,6 +222,12 @@ $selectOptions = array(
|
||||
$('#howGetIPs-trusted-proxies').addClass('wf-active');
|
||||
}
|
||||
});
|
||||
|
||||
$('#howGetIPs-trusted-proxy-preset').slideDown({
|
||||
always: function() {
|
||||
$('#howGetIPs-trusted-proxy-preset').addClass('wf-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,7 +46,22 @@ foreach ($diagnostic->getResults() as $title => $tests):
|
||||
$message = '[FAIL] ';
|
||||
}
|
||||
|
||||
$message .= strip_tags($result['message'] . (isset($result['detail']) && !empty($result['detail']) ? "\nAdditional Detail:\n" . $result['detail'] : ''));
|
||||
if (is_array($result['message'])) {
|
||||
$message .= $result['message']['textonly'];
|
||||
}
|
||||
else {
|
||||
$message .= strip_tags($result['message']);
|
||||
}
|
||||
|
||||
if (isset($result['detail']) && !empty($result['detail'])) {
|
||||
$message .= "\nAdditional Detail:\n";
|
||||
if (is_array($result['detail'])) {
|
||||
$message .= $result['detail']['textonly'];
|
||||
}
|
||||
else {
|
||||
$message .= strip_tags($result['detail']);
|
||||
}
|
||||
}
|
||||
|
||||
$table[] = array(
|
||||
strip_tags((is_array($result['label']) && isset($result['label']['raw']) && $result['label']['raw']) ? $result['label']['value'] : $result['label']),
|
||||
@@ -104,9 +119,18 @@ foreach (wfUtils::getAllServerVariableIPs() as $variable => $ip) {
|
||||
);
|
||||
}
|
||||
|
||||
$proxies = wfConfig::get('howGetIPs_trusted_proxies', '');
|
||||
$table[] = array(
|
||||
__('Trusted Proxies', 'wordfence'),
|
||||
strip_tags(implode(', ', explode("\n", wfConfig::get('howGetIPs_trusted_proxies', '')))),
|
||||
strip_tags(implode(', ', explode("\n", empty($proxies) ? __('(not set)', 'wordfence') : $proxies))),
|
||||
'',
|
||||
);
|
||||
|
||||
$preset = wfConfig::get('howGetIPs_trusted_proxy_preset');
|
||||
$presets = wfConfig::getJSON('ipResolutionList', array());
|
||||
$table[] = array(
|
||||
__('Trusted Proxy Preset', 'wordfence'),
|
||||
strip_tags((is_array($presets) && isset($presets[$preset])) ? $presets[$preset]['name'] : __('(not set)', 'wordfence')),
|
||||
'',
|
||||
);
|
||||
|
||||
@@ -340,8 +364,8 @@ echo wfHelperString::plainTextTable($table) . "\n\n";
|
||||
global $wpdb;
|
||||
$wfdb = new wfDB();
|
||||
//This must be done this way because MySQL with InnoDB tables does a full regeneration of all metadata if we don't. That takes a long time with a large table count.
|
||||
$tables = $wfdb->querySelect('SELECT SQL_CALC_FOUND_ROWS TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() ORDER BY TABLE_NAME ASC LIMIT 250');
|
||||
$total = $wfdb->querySingle('SELECT FOUND_ROWS()');
|
||||
$tables = $wfdb->querySelect('SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() ORDER BY TABLE_NAME ASC LIMIT 250');
|
||||
$total = $wfdb->querySingle('SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() LIMIT 250');
|
||||
foreach ($tables as &$t) {
|
||||
$t = "'" . esc_sql($t['TABLE_NAME']) . "'";
|
||||
}
|
||||
@@ -389,8 +413,11 @@ if ($q) {
|
||||
} else {
|
||||
printf(/* translators: 1. WordPress table prefix. 2. Wordfence tables. */ __('Tables missing (prefix %1$s, %2$s): %s', 'wordfence'), wfDB::networkPrefix(), wfSchema::usingLowercase() ? __('lowercase', 'wordfence') : __('regular case', 'wordfence'), implode(', ', $missingTables));
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
printf(/* translators: 1. Number of tables */ _n('%1$s Table in Database', '%1$s Tables in Database', $total, 'wordfence' ), $total );
|
||||
echo "\n";
|
||||
|
||||
$val = wfUtils::array_first($q);
|
||||
$actualKeyOrder = array_keys($val);
|
||||
|
||||
@@ -236,6 +236,7 @@ if (!isset($collapseable)) {
|
||||
'disabledValue' => 0,
|
||||
'value' => wfConfig::get('other_blockBadPOST') ? 1 : 0,
|
||||
'title' => __('Block IPs who send POST requests with blank User-Agent and Referer', 'wordfence'),
|
||||
'subtitleHTML' => esc_html__('If you use external services that may send POST requests without these headers, do not use this option, as they will be blocked.', 'wordfence'),
|
||||
'helpLink' => wfSupportController::supportURL(wfSupportController::ITEM_FIREWALL_WAF_OPTION_BLOCK_BAD_POST),
|
||||
))->render();
|
||||
?>
|
||||
|
||||
@@ -131,7 +131,7 @@ class wfWAFWordPressRequest extends wfWAFRequest {
|
||||
continue; //This was an array so we can skip to the next item
|
||||
}
|
||||
$skipToNext = false;
|
||||
$trustedProxyConfig = wfWAF::getInstance()->getStorageEngine()->getConfig('howGetIPs_trusted_proxies', null, 'synced');
|
||||
$trustedProxyConfig = wfWAF::getInstance()->getStorageEngine()->getConfig('howGetIPs_trusted_proxies_unified', null, 'synced');
|
||||
$trustedProxies = $trustedProxyConfig === null ? array() : explode("\n", $trustedProxyConfig);
|
||||
foreach (array(',', ' ', "\t") as $char) {
|
||||
if (strpos($item, $char) !== false) {
|
||||
|
||||
@@ -4,7 +4,7 @@ Plugin Name: Wordfence Security
|
||||
Plugin URI: http://www.wordfence.com/
|
||||
Description: Wordfence Security - Anti-virus, Firewall and Malware Scan
|
||||
Author: Wordfence
|
||||
Version: 7.10.7
|
||||
Version: 7.11.1
|
||||
Author URI: http://www.wordfence.com/
|
||||
Text Domain: wordfence
|
||||
Domain Path: /languages
|
||||
@@ -38,8 +38,8 @@ if(defined('WP_INSTALLING') && WP_INSTALLING){
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
define('WORDFENCE_VERSION', '7.10.7');
|
||||
define('WORDFENCE_BUILD_NUMBER', '1699289814');
|
||||
define('WORDFENCE_VERSION', '7.11.1');
|
||||
define('WORDFENCE_BUILD_NUMBER', '1704213472');
|
||||
define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
|
||||
basename(dirname(__FILE__)) . '/' . basename(__FILE__));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user