Diff
13 years ago
.htaccess
14 years ago
Diff.php
13 years ago
IPTraf.php
13 years ago
diffResult.php
13 years ago
email_genericAlert.php
13 years ago
email_newIssues.php
14 years ago
email_unlockRequest.php
14 years ago
menu_activity.php
14 years ago
menu_blockedIPs.php
13 years ago
menu_options.php
13 years ago
menu_scan.php
13 years ago
sysinfo.php
13 years ago
viewFullActivityLog.php
13 years ago
wf503.php
13 years ago
wfAPI.php
13 years ago
wfAction.php
14 years ago
wfArray.php
13 years ago
wfBrowscap.php
14 years ago
wfBrowscapCache.php
14 years ago
wfConfig.php
13 years ago
wfCrawl.php
13 years ago
wfDB.php
13 years ago
wfDict.php
14 years ago
wfIssues.php
13 years ago
wfLockedOut.php
14 years ago
wfLog.php
13 years ago
wfModTracker.php
14 years ago
wfRate.php
14 years ago
wfScanEngine.php
13 years ago
wfSchema.php
13 years ago
wfUnlockMsg.php
14 years ago
wfUtils.php
13 years ago
wfViewResult.php
13 years ago
wordfenceClass.php
13 years ago
wordfenceConstants.php
13 years ago
wordfenceHash.php
13 years ago
wordfenceScanner.php
13 years ago
wordfenceURLHoover.php
13 years ago
wfIssues.php
254 lines
| 1 | <?php |
| 2 | require_once('wfUtils.php'); |
| 3 | class wfIssues { |
| 4 | private $db = false; |
| 5 | |
| 6 | //Properties that are serialized on sleep: |
| 7 | private $updateCalled = false; |
| 8 | private $issuesTable = ''; |
| 9 | private $newIssues = array(); |
| 10 | public $totalIssues = 0; |
| 11 | public $totalCriticalIssues = 0; |
| 12 | public $totalWarningIssues = 0; |
| 13 | public function __sleep(){ //Same order here as vars above |
| 14 | return array('updateCalled', 'issuesTable', 'newIssues', 'totalIssues', 'totalCriticalIssues', 'totalWarningIssues'); |
| 15 | } |
| 16 | public function __construct(){ |
| 17 | global $wpdb; |
| 18 | $this->issuesTable = $wpdb->base_prefix . 'wfIssues'; |
| 19 | } |
| 20 | public function __wakeup(){ |
| 21 | $this->db = new wfDB(); |
| 22 | } |
| 23 | public function addIssue($type, $severity, |
| 24 | |
| 25 | $ignoreP, /* some piece of data used for md5 for permanent ignores */ |
| 26 | $ignoreC, /* some piece of data used for md5 for ignoring until something changes */ |
| 27 | $shortMsg, $longMsg, $templateData |
| 28 | ){ |
| 29 | |
| 30 | |
| 31 | $ignoreP = md5($ignoreP); |
| 32 | $ignoreC = md5($ignoreC); |
| 33 | $rec = $this->getDB()->querySingleRec("select status, ignoreP, ignoreC from " . $this->issuesTable . " where (ignoreP='%s' OR ignoreC='%s')", $ignoreP, $ignoreC); |
| 34 | if($rec){ |
| 35 | if($rec['status'] == 'new' && ($rec['ignoreC'] == $ignoreC || $rec['ignoreP'] == $ignoreP)){ return false; } |
| 36 | if($rec['status'] == 'ignoreC' && $rec['ignoreC'] == $ignoreC){ return false; } |
| 37 | if($rec['status'] == 'ignoreP' && $rec['ignoreP'] == $ignoreP){ return false; } |
| 38 | } |
| 39 | |
| 40 | if($severity == 1){ |
| 41 | $this->totalCriticalIssues++; |
| 42 | } else if($severity == 2){ |
| 43 | $this->totalWarningIssues++; |
| 44 | } |
| 45 | $this->totalIssues++; |
| 46 | $this->newIssues[] = array( |
| 47 | 'type' => $type, |
| 48 | 'severity' => $severity, |
| 49 | 'ignoreP' => $ignoreP, |
| 50 | 'ignoreC' => $ignoreC, |
| 51 | 'shortMsg' => $shortMsg, |
| 52 | 'longMsg' => $longMsg, |
| 53 | 'tmplData' => $templateData |
| 54 | ); |
| 55 | |
| 56 | $this->getDB()->query("insert into " . $this->issuesTable . " (time, status, type, severity, ignoreP, ignoreC, shortMsg, longMsg, data) values (unix_timestamp(), '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s')", |
| 57 | 'new', |
| 58 | $type, |
| 59 | $severity, |
| 60 | $ignoreP, |
| 61 | $ignoreC, |
| 62 | $shortMsg, |
| 63 | $longMsg, |
| 64 | serialize($templateData) |
| 65 | ); |
| 66 | return true; |
| 67 | } |
| 68 | public function deleteIgnored(){ |
| 69 | $this->getDB()->query("delete from " . $this->issuesTable . " where status='ignoreP' or status='ignoreC'"); |
| 70 | } |
| 71 | public function deleteNew(){ |
| 72 | $this->getDB()->query("delete from " . $this->issuesTable . " where status='new'"); |
| 73 | } |
| 74 | public function ignoreAllNew(){ |
| 75 | $this->getDB()->query("update " . $this->issuesTable . " set status='ignoreC' where status='new'"); |
| 76 | } |
| 77 | public function emailNewIssues(){ |
| 78 | $level = wfConfig::getAlertLevel(); |
| 79 | $emails = wfConfig::getAlertEmails(); |
| 80 | $subject = "[Wordfence Alert] Problems found on " . get_bloginfo('name', 'raw'); |
| 81 | |
| 82 | if(sizeof($emails) < 1){ return; } |
| 83 | if($level < 1){ return; } |
| 84 | if($level == 2 && $this->totalCriticalIssues < 1 && $this->totalWarningIssues < 1){ return; } |
| 85 | if($level == 1 && $this->totalCriticalIssues < 1){ return; } |
| 86 | $emailedIssues = wfConfig::get_ser('emailedIssuesList', array()); |
| 87 | if(! is_array($emailedIssues)){ |
| 88 | $emailedIssues = array(); |
| 89 | } |
| 90 | $finalIssues = array(); |
| 91 | foreach($this->newIssues as $newIssue){ |
| 92 | $alreadyEmailed = false; |
| 93 | foreach($emailedIssues as $emailedIssue){ |
| 94 | if($newIssue['ignoreP'] == $emailedIssue['ignoreP'] || $newIssue['ignoreC'] == $emailedIssue['ignoreC']){ |
| 95 | $alreadyEmailed = true; |
| 96 | break; |
| 97 | } |
| 98 | } |
| 99 | if(! $alreadyEmailed){ |
| 100 | $finalIssues[] = $newIssue; |
| 101 | } |
| 102 | } |
| 103 | if(sizeof($finalIssues) < 1){ return; } |
| 104 | |
| 105 | $totalWarningIssues = 0; |
| 106 | $totalCriticalIssues = 0; |
| 107 | foreach($finalIssues as $i){ |
| 108 | $emailedIssues[] = array( 'ignoreC' => $i['ignoreC'], 'ignoreP' => $i['ignoreP'] ); |
| 109 | if($i['severity'] == 1){ |
| 110 | $totalCriticalIssues++; |
| 111 | } else if($i['severity'] == 2){ |
| 112 | $totalWarningIssues++; |
| 113 | } |
| 114 | } |
| 115 | wfConfig::set_ser('emailedIssuesList', $emailedIssues); |
| 116 | if($level == 2 && $totalCriticalIssues < 1 && $totalWarningIssues < 1){ return; } |
| 117 | if($level == 1 && $totalCriticalIssues < 1){ return; } |
| 118 | $content = wfUtils::tmpl('email_newIssues.php', array( |
| 119 | 'issues' => $finalIssues, |
| 120 | 'totalCriticalIssues' => $totalCriticalIssues, |
| 121 | 'totalWarningIssues' => $totalWarningIssues, |
| 122 | 'level' => $level |
| 123 | )); |
| 124 | wp_mail(implode(',', $emails), $subject, $content); |
| 125 | } |
| 126 | public function deleteIssue($id){ |
| 127 | $this->getDB()->query("delete from " . $this->issuesTable . " where id=%d", $id); |
| 128 | } |
| 129 | public function updateIssue($id, $status){ //ignoreC, ignoreP, delete or new |
| 130 | $currentStatus = $this->getDB()->querySingle("select status from " . $this->issuesTable . " where id=%d", $id); |
| 131 | if($status == 'delete'){ |
| 132 | $this->getDB()->query("delete from " . $this->issuesTable . " where id=%d", $id); |
| 133 | } else if($status == 'ignoreC' || $status == 'ignoreP' || $status == 'new'){ |
| 134 | $this->getDB()->query("update " . $this->issuesTable . " set status='%s' where id=%d", $status, $id); |
| 135 | } |
| 136 | } |
| 137 | public function getIssueByID($id){ |
| 138 | $rec = $this->getDB()->querySingleRec("select * from " . $this->issuesTable . " where id=%d", $id); |
| 139 | $rec['data'] = unserialize($rec['data']); |
| 140 | return $rec; |
| 141 | } |
| 142 | public function getIssues(){ |
| 143 | $issues = wfConfig::get('wf_issues', array()); |
| 144 | $ret = array( |
| 145 | 'new' => array(), |
| 146 | 'ignored' => array() |
| 147 | ); |
| 148 | $q1 = $this->getDB()->query("select * from " . $this->issuesTable . " order by time desc"); |
| 149 | while($i = mysql_fetch_assoc($q1)){ |
| 150 | $i['data'] = unserialize($i['data']); |
| 151 | $i['timeAgo'] = wfUtils::makeTimeAgo(time() - $i['time']); |
| 152 | if($i['status'] == 'new'){ |
| 153 | $ret['new'][] = $i; |
| 154 | } else if($i['status'] == 'ignoreP' || $i['status'] == 'ignoreC'){ |
| 155 | $ret['ignored'][] = $i; |
| 156 | } else { |
| 157 | error_log("Issue has bad status: " . $i['status']); |
| 158 | continue; |
| 159 | } |
| 160 | } |
| 161 | foreach($ret as $status => &$issueList){ |
| 162 | for($i = 0; $i < sizeof($issueList); $i++){ |
| 163 | if($issueList[$i]['type'] == 'file'){ |
| 164 | $localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $issueList[$i]['data']['file']); |
| 165 | if(file_exists($localFile)){ |
| 166 | $issueList[$i]['data']['fileExists'] = true; |
| 167 | } else { |
| 168 | $issueList[$i]['data']['fileExists'] = ''; |
| 169 | } |
| 170 | } |
| 171 | $issueList[$i]['issueIDX'] = $i; |
| 172 | } |
| 173 | } |
| 174 | return $ret; //array of lists of issues by status |
| 175 | } |
| 176 | public function updateSummaryItem($key, $val){ |
| 177 | $arr = wfConfig::get_ser('wf_summaryItems', array()); |
| 178 | $arr[$key] = $val; |
| 179 | $arr['lastUpdate'] = time(); |
| 180 | wfConfig::set_ser('wf_summaryItems', $arr); |
| 181 | } |
| 182 | public function getSummaryItem($key){ |
| 183 | $arr = wfConfig::get_ser('wf_summaryItems', array()); |
| 184 | if(array_key_exists($key, $arr)){ |
| 185 | return $arr[$key]; |
| 186 | } else { return ''; } |
| 187 | } |
| 188 | public function summaryUpdateRequired(){ |
| 189 | $last = $this->getSummaryItem('lastUpdate'); |
| 190 | if( (! $last) || (time() - $last > (86400 * 7))){ |
| 191 | return true; |
| 192 | } |
| 193 | return false; |
| 194 | } |
| 195 | public function getSummaryItems(){ |
| 196 | if(! $this->updateCalled){ |
| 197 | $this->updateCalled = true; |
| 198 | $this->updateSummaryItems(); |
| 199 | } |
| 200 | $arr = wfConfig::get_ser('wf_summaryItems', array()); |
| 201 | //$arr['scanTimeAgo'] = wfUtils::makeTimeAgo(sprintf('%.0f', time() - $arr['scanTime'])); |
| 202 | $arr['scanRunning'] = wfUtils::isScanRunning() ? '1' : '0'; |
| 203 | $arr['scheduledScansEnabled'] = wfConfig::get('scheduledScansEnabled'); |
| 204 | $secsToGo = wp_next_scheduled('wordfence_scheduled_scan') - time(); |
| 205 | if($secsToGo < 1){ |
| 206 | $nextRun = 'now'; |
| 207 | } else { |
| 208 | $nextRun = wfUtils::makeTimeAgo($secsToGo) . ' from now'; |
| 209 | } |
| 210 | $arr['nextRun'] = $nextRun; |
| 211 | |
| 212 | $arr['totalCritical'] = $this->getDB()->querySingle("select count(*) as cnt from " . $this->issuesTable . " where status='new' and severity=1"); |
| 213 | $arr['totalWarning'] = $this->getDB()->querySingle("select count(*) as cnt from " . $this->issuesTable . " where status='new' and severity=2"); |
| 214 | |
| 215 | return $arr; |
| 216 | } |
| 217 | private function updateSummaryItems(){ |
| 218 | global $wpdb; |
| 219 | $dat = array(); |
| 220 | $users = $wpdb->get_col($wpdb->prepare("SELECT $wpdb->users.ID FROM $wpdb->users")); |
| 221 | $dat['totalUsers'] = sizeof($users); |
| 222 | $res1 = $wpdb->get_col($wpdb->prepare("SELECT count(*) as cnt FROM $wpdb->posts where post_type='page' and post_status NOT IN ('auto-draft')")); $dat['totalPages'] = $res1['0']; |
| 223 | $res1 = $wpdb->get_col($wpdb->prepare("SELECT count(*) as cnt FROM $wpdb->posts where post_type='post' and post_status NOT IN ('auto-draft')")); $dat['totalPosts'] = $res1['0']; |
| 224 | $res1 = $wpdb->get_col($wpdb->prepare("SELECT count(*) as cnt FROM $wpdb->comments")); $dat['totalComments'] = $res1['0']; |
| 225 | $res1 = $wpdb->get_col($wpdb->prepare("SELECT count(*) as cnt FROM $wpdb->term_taxonomy where taxonomy='category'")); $dat['totalCategories'] = $res1['0']; |
| 226 | $res1 = $wpdb->get_col($wpdb->prepare("show tables")); $dat['totalTables'] = sizeof($res1); |
| 227 | $totalRows = 0; |
| 228 | foreach($res1 as $table){ |
| 229 | $res2 = $wpdb->get_col($wpdb->prepare("select count(*) from $table")); |
| 230 | $totalRows += $res2[0]; |
| 231 | } |
| 232 | $dat['totalRows'] = $totalRows; |
| 233 | $arr = wfConfig::get_ser('wf_summaryItems', array()); |
| 234 | foreach($dat as $key => $val){ |
| 235 | $arr[$key] = $val; |
| 236 | } |
| 237 | wfConfig::set_ser('wf_summaryItems', $arr); |
| 238 | } |
| 239 | public function setScanTimeNow(){ |
| 240 | $this->updateSummaryItem('scanTime', microtime(true)); |
| 241 | } |
| 242 | public function getScanTime(){ |
| 243 | return $this->getSummaryItem('scanTime'); |
| 244 | } |
| 245 | private function getDB(){ |
| 246 | if(! $this->db){ |
| 247 | $this->db = new wfDB(); |
| 248 | } |
| 249 | return $this->db; |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | ?> |
| 254 |