PluginProbe ʕ •ᴥ•ʔ
Wordfence Security – Firewall, Malware Scan, and Login Security / 3.8.2
Wordfence Security – Firewall, Malware Scan, and Login Security v3.8.2
8.2.2 8.2.1 8.2.0 3.7.1 3.7.2 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.8.8 3.8.9 3.9.1 4.0.1 4.0.2 4.0.3 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.0.9 5.1.1 5.1.2 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.1 5.3.10 5.3.11 5.3.12 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.3.8 5.3.9 6.0.1 6.0.10 6.0.11 6.0.12 6.0.14 6.0.15 6.0.16 6.0.17 6.0.18 6.0.19 6.0.2 6.0.20 6.0.21 6.0.22 6.0.23 6.0.24 6.0.25 6.0.3 6.0.4 6.0.5 6.0.6 6.0.7 6.0.8 6.0.9 6.1.1 6.1.10 6.1.11 6.1.12 6.1.14 6.1.15 6.1.16 6.1.17 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.1.8 6.1.9 6.2.0 6.2.1 6.2.10 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.2.8 6.2.9 6.3.0 6.3.1 6.3.10 6.3.11 6.3.12 6.3.14 6.3.15 6.3.16 6.3.17 6.3.18 6.3.19 6.3.2 6.3.20 6.3.21 6.3.22 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.3.8 6.3.9 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1.0 7.1.1 7.1.10 7.1.11 7.1.12 7.1.14 7.1.15 7.1.16 7.1.17 7.1.18 7.1.19 7.1.2 7.1.20 7.1.3 7.1.4 7.1.5 7.1.6 7.1.7 7.1.8 7.1.9 7.10.0 7.10.1 7.10.2 7.10.3 7.10.4 7.10.5 7.10.6 7.10.7 7.11.0 7.11.1 7.11.2 7.11.3 7.11.4 7.11.5 7.11.6 7.11.7 7.2.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.4.0 7.4.1 7.4.10 7.4.11 7.4.12 7.4.14 7.4.2 7.4.3 trunk 7.4.4 1.1 7.4.5 1.2 7.4.6 1.3 7.4.7 1.3.1 7.4.8 1.3.2 7.4.9 1.3.3 7.5.0 1.4.2 7.5.1 1.4.3 7.5.10 1.4.4 7.5.11 1.4.5 7.5.2 1.4.6 7.5.3 1.4.7 7.5.4 1.4.8 7.5.5 1.5.1 7.5.6 1.5.2 7.5.7 1.5.3 7.5.8 1.5.4 7.5.9 1.5.5 7.6.0 1.5.6 7.6.1 2.0.1 7.6.2 2.0.2 7.7.0 2.0.3 7.7.1 2.0.5 7.8.0 2.0.6 7.8.1 2.0.7 7.8.2 2.1.0 7.9.0 2.1.1 7.9.1 2.1.2 7.9.2 2.1.3 7.9.3 2.1.4 8.0.0 2.1.5 8.0.1 3.0.2 8.0.2 3.0.3 8.0.3 3.0.4 8.0.4 3.0.5 8.0.5 3.0.6 8.1.0 3.0.7 8.1.1 3.0.8 8.1.2 3.0.9 8.1.3 3.1.0 8.1.4 3.1.1 v1.4.1 3.1.2 3.1.4 3.1.6 3.2.1 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.1 3.4.4 3.4.5 3.5.1 3.5.2 3.6.1 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9
wordfence / js / admin.js
wordfence / js Last commit date
admin.js 12 years ago jquery.colorbox-min.js 14 years ago jquery.dataTables.min.js 14 years ago jquery.tmpl.min.js 14 years ago jquery.tools.min.js 14 years ago tourTip.js 12 years ago
admin.js
1367 lines
1 if(! window['wordfenceAdmin']){ //To compile for checking: java -jar /usr/local/bin/closure.jar --js=admin.js --js_output_file=test.js
2 window['wordfenceAdmin'] = {
3 loading16: '<div class="wfLoading16"></div>',
4 loadingCount: 0,
5 dbCheckTables: [],
6 dbCheckCount_ok: 0,
7 dbCheckCount_skipped: 0,
8 dbCheckCount_errors: 0,
9 issues: [],
10 ignoreData: false,
11 iconErrorMsgs: [],
12 scanIDLoaded: 0,
13 colorboxQueue: [],
14 colorboxOpen: false,
15 mode: '',
16 visibleIssuesPanel: 'new',
17 preFirstScanMsgsLoaded: false,
18 newestActivityTime: 0, //must be 0 to force loading of all initially
19 elementGeneratorIter: 1,
20 reloadConfigPage: false,
21 nonce: false,
22 tickerUpdatePending: false,
23 activityLogUpdatePending: false,
24 lastALogCtime: 0,
25 activityQueue: [],
26 totalActAdded: 0,
27 maxActivityLogItems: 1000,
28 scanReqAnimation: false,
29 debugOn: false,
30 blockedCountriesPending: [],
31 ownCountry: "",
32 schedStartHour: false,
33 currentPointer: false,
34 countryMap: false,
35 countryCodesToSave: "",
36 init: function(){
37 this.nonce = WordfenceAdminVars.firstNonce;
38 this.debugOn = WordfenceAdminVars.debugOn == '1' ? true : false;
39 this.tourClosed = WordfenceAdminVars.tourClosed == '1' ? true : false;
40 var startTicker = false;
41 if(jQuery('#wordfenceMode_scan').length > 0){
42 this.mode = 'scan';
43 jQuery('#wfALogViewLink').prop('href', WordfenceAdminVars.siteBaseURL + '?_wfsf=viewActivityLog&nonce=' + this.nonce);
44 jQuery('#consoleActivity').scrollTop(jQuery('#consoleActivity').prop('scrollHeight'));
45 jQuery('#consoleScan').scrollTop(jQuery('#consoleScan').prop('scrollHeight'));
46 this.noScanHTML = jQuery('#wfNoScanYetTmpl').tmpl().html();
47 this.loadIssues();
48 this.startActivityLogUpdates();
49 if(! this.tourClosed){
50 this.scanTourStart();
51 }
52 } else if(jQuery('#wordfenceMode_activity').length > 0){
53 this.mode = 'activity';
54 this.activityMode = 'hit';
55 startTicker = true;
56 if(! this.tourClosed){
57 var self = this;
58 this.tour('wfWelcomeContent3', 'wfHeading', 'top', 'left', "Learn about IP Blocking", function(){ self.tourRedir('WordfenceBlockedIPs'); });
59 }
60 } else if(jQuery('#wordfenceMode_options').length > 0){
61 this.mode = 'options';
62 jQuery('.wfConfigElem').change(function(){ jQuery('#securityLevel').val('CUSTOM'); });
63 this.updateTicker(true);
64 startTicker = true;
65 if(! this.tourClosed){
66 var self = this;
67 this.tour('wfContentBasicOptions', 'wfMarkerBasicOptions', 'top', 'left', "Learn about Live Traffic Options", function(){
68 self.tour('wfContentLiveTrafficOptions', 'wfMarkerLiveTrafficOptions', 'bottom', 'left', "Learn about Scanning Options", function(){
69 self.tour('wfContentScansToInclude', 'wfMarkerScansToInclude', 'bottom', 'left', "Learn about Firewall Rules", function(){
70 self.tour('wfContentFirewallRules', 'wfMarkerFirewallRules', 'bottom', 'left', "Learn about Login Security", function(){
71 self.tour('wfContentLoginSecurity', 'wfMarkerLoginSecurity', 'bottom', 'left', "Learn about Other Options", function(){
72 self.tour('wfContentOtherOptions', 'wfMarkerOtherOptions', 'bottom', 'left', false, false);
73 });
74 });
75 });
76 });
77 });
78 }
79 } else if(jQuery('#wordfenceMode_blockedIPs').length > 0){
80 this.mode = 'blocked';
81 this.staticTabChanged();
82 this.updateTicker(true);
83 startTicker = true;
84 if(! this.tourClosed){
85 var self = this;
86 this.tour('wfWelcomeContent4', 'wfHeading', 'top', 'left', "Learn about Cellphone Sign-in", function(){ self.tourRedir('WordfenceTwoFactor'); });
87 }
88 } else if(jQuery('#wordfenceMode_twoFactor').length > 0){
89 this.mode = 'twoFactor';
90 startTicker = false;
91 if(! this.tourClosed){
92 var self = this;
93 this.tour('wfWelcomeTwoFactor', 'wfHeading', 'top', 'left', "Learn how to Block Countries", function(){ self.tourRedir('WordfenceCountryBlocking'); });
94 }
95 this.loadTwoFactor();
96
97 } else if(jQuery('#wordfenceMode_countryBlocking').length > 0){
98 this.mode = 'countryBlocking';
99 startTicker = false;
100 if(! this.tourClosed){
101 var self = this;
102 this.tour('wfWelcomeContentCntBlk', 'wfHeading', 'top', 'left', "Learn how to Schedule Scans", function(){ self.tourRedir('WordfenceScanSchedule'); });
103 }
104 } else if(jQuery('#wordfenceMode_rangeBlocking').length > 0){
105 this.mode = 'rangeBlocking';
106 startTicker = false;
107 if(! this.tourClosed){
108 var self = this;
109 this.tour('wfWelcomeContentRangeBlocking', 'wfHeading', 'top', 'left', "Learn how to Customize Wordfence", function(){ self.tourRedir('WordfenceSecOpt'); });
110 }
111 this.calcRangeTotal();
112 this.loadBlockRanges();
113 } else if(jQuery('#wordfenceMode_whois').length > 0){
114 this.mode = 'whois';
115 startTicker = false;
116 if(! this.tourClosed){
117 var self = this;
118 this.tour('wfWelcomeContentWhois', 'wfHeading', 'top', 'left', "Learn how to use Advanced Blocking", function(){ self.tourRedir('WordfenceRangeBlocking'); });
119 }
120 this.calcRangeTotal();
121 this.loadBlockRanges();
122
123 } else if(jQuery('#wordfenceMode_scanScheduling').length > 0){
124 this.mode = 'scanScheduling';
125 startTicker = false;
126 this.sched_modeChange();
127 if(! this.tourClosed){
128 var self = this;
129 this.tour('wfWelcomeContentScanSched', 'wfHeading', 'top', 'left', "Learn about WHOIS", function(){ self.tourRedir('WordfenceWhois'); });
130 }
131 } else {
132 this.mode = false;
133 }
134 if(this.mode){ //We are in a Wordfence page
135 var self = this;
136 if(startTicker){
137 this.liveInt = setInterval(function(){ self.updateTicker(); }, WordfenceAdminVars.actUpdateInterval);
138 }
139 jQuery(document).bind('cbox_closed', function(){ self.colorboxIsOpen = false; self.colorboxServiceQueue(); });
140 }
141 },
142 scanTourStart: function(){
143 var self = this;
144 this.tour('wfWelcomeContent1', 'wfHeading', 'top', 'left', "Continue the Tour", function(){
145 self.tour('wfWelcomeContent2', 'wfHeading', 'top', 'left', "Learn how to use Wordfence", function(){
146 self.tour('wfWelcomeContent3', 'wfHeading', 'top', 'left', "Learn about Live Traffic", function(){ self.tourRedir('WordfenceActivity'); });
147 });
148 });
149 },
150 tourRedir: function(menuItem){
151 window.location.href = 'admin.php?page=' + menuItem;
152 },
153 tourFinish: function(){
154 this.ajax('wordfence_tourClosed', {}, function(res){});
155 },
156 downgradeLicense: function(){
157 this.colorbox('400px', "Confirm Downgrade", "Are you sure you want to downgrade your Wordfence Premium License? This will disable all Premium features and return you to the free version of Wordfence. <a href=\"https://www.wordfence.com/manage-wordfence-api-keys/\" target=\"_blank\">Click here to renew your paid membership</a> or click the button below to confirm you want to downgrade.<br /><br /><input type=\"button\" value=\"Downgrade and disable Premium features\" onclick=\"WFAD.downgradeLicenseConfirm();\" /><br />");
158 },
159 downgradeLicenseConfirm: function(){
160 jQuery.colorbox.close();
161 this.ajax('wordfence_downgradeLicense', {}, function(res){ location.reload(true); });
162 },
163 tour: function(contentID, elemID, edge, align, buttonLabel, buttonCallback){
164 var self = this;
165 if(this.currentPointer){
166 this.currentPointer.pointer('destroy');
167 this.currentPointer = false;
168 }
169 var options = {
170 buttons: function(event, t){
171 var buttonElem = jQuery('<div id="wfTourButCont"><a id="pointer-close" style="margin-left:5px" class="button-secondary">End the Tour</a></div><div><a id="wfRateLink" href="http://wordpress.org/extend/plugins/wordfence/" target="_blank" style="font-size: 10px; font-family: Verdana;">Help spread the word by rating us 5&#9733; on WordPress.org</a></div>');
172 buttonElem.find('#pointer-close').bind('click.pointer', function (evtObj) {
173 var evtSourceElem = evtObj.srcElement ? evtObj.srcElement : evtObj.target;
174 if(evtSourceElem.id == 'wfRateLink'){
175 return true;
176 }
177 self.tourFinish();
178 t.element.pointer('close');
179 return false;
180 });
181 return buttonElem;
182 },
183 close: function(){},
184 content: jQuery('#' + contentID).tmpl().html(),
185 pointerWidth: 400,
186 position: {
187 edge: edge,
188 align: align
189 }
190 };
191 this.currentPointer = jQuery('#' + elemID).pointer(options).pointer('open');
192 if(buttonLabel && buttonCallback){
193 jQuery('#pointer-close').after('<a id="pointer-primary" class="button-primary">' + buttonLabel + '</a>');
194 jQuery('#pointer-primary').click(buttonCallback);
195 }
196 },
197 startTourAgain: function(){
198 this.ajax('wordfence_startTourAgain', {}, function(res){});
199 this.tourClosed = false;
200 this.scanTourStart();
201 },
202 showLoading: function(){
203 this.loadingCount++;
204 if(this.loadingCount == 1){
205 jQuery('<div id="wordfenceWorking">Wordfence is working...</div>').appendTo('body');
206 }
207 },
208 removeLoading: function(){
209 this.loadingCount--;
210 if(this.loadingCount == 0){
211 jQuery('#wordfenceWorking').remove();
212 }
213 },
214 startActivityLogUpdates: function(){
215 var self = this;
216 setInterval(function(){
217 self.updateActivityLog();
218 }, parseInt(WordfenceAdminVars.actUpdateInterval));
219 },
220 updateActivityLog: function(){
221 if(this.activityLogUpdatePending){
222 return;
223 }
224 this.activityLogUpdatePending = true;
225 var self = this;
226 this.ajax('wordfence_activityLogUpdate', {
227 lastctime: this.lastALogCtime
228 }, function(res){ self.doneUpdateActivityLog(res); }, function(){ self.activityLogUpdatePending = false; }, true);
229
230 },
231 doneUpdateActivityLog: function(res){
232 this.actNextUpdateAt = (new Date()).getTime() + parseInt(WordfenceAdminVars.actUpdateInterval);
233 if(res.ok){
234 if(res.items.length > 0){
235 this.activityQueue.push.apply(this.activityQueue, res.items);
236 this.lastALogCtime = res.items[res.items.length - 1].ctime;
237 this.processActQueue(res.currentScanID);
238 }
239 }
240 this.activityLogUpdatePending = false;
241 },
242 processActQueue: function(currentScanID){
243 if(this.activityQueue.length > 0){
244 this.addActItem(this.activityQueue.shift());
245 this.totalActAdded++;
246 if(this.totalActAdded > this.maxActivityLogItems){
247 jQuery('#consoleActivity div:first').remove();
248 this.totalActAdded--;
249 }
250 var timeTillNextUpdate = this.actNextUpdateAt - (new Date()).getTime();
251 var maxRate = 50 / 1000; //Rate per millisecond
252 var bulkTotal = 0;
253 while(this.activityQueue.length > 0 && this.activityQueue.length / timeTillNextUpdate > maxRate ){
254 var item = this.activityQueue.shift();
255 if(item){
256 bulkTotal++;
257 this.addActItem(item);
258 }
259 }
260 this.totalActAdded += bulkTotal;
261 if(this.totalActAdded > this.maxActivityLogItems){
262 jQuery('#consoleActivity div:lt(' + bulkTotal + ')').remove();
263 this.totalActAdded -= bulkTotal;
264 }
265 var minDelay = 100;
266 var delay = minDelay;
267 if(timeTillNextUpdate < 1){
268 delay = minDelay;
269 } else {
270 delay = Math.round(timeTillNextUpdate / this.activityQueue.length);
271 if(delay < minDelay){ delay = minDelay; }
272 }
273 var self = this;
274 setTimeout(function(){ self.processActQueue(); }, delay);
275 }
276 jQuery('#consoleActivity').scrollTop(jQuery('#consoleActivity').prop('scrollHeight'));
277 },
278 processActArray: function(arr){
279 for(var i = 0; i < arr.length; i++){
280 this.addActItem(arr[i]);
281 }
282 },
283 addActItem: function(item){
284 if(! item){ return; }
285 if(! item.msg){ return; }
286 if(item.msg.indexOf('SUM_') == 0){
287 this.processSummaryLine(item);
288 jQuery('#consoleSummary').scrollTop(jQuery('#consoleSummary').prop('scrollHeight'));
289 jQuery('#wfStartingScan').addClass('wfSummaryOK').html('Done.');
290 } else if(this.debugOn || item.level < 4){
291
292 var html = '<div class="wfActivityLine';
293 if(this.debugOn){
294 html += ' wf' + item.type;
295 }
296 html += '">[' + item.date + ']&nbsp;' + item.msg + '</div>';
297 jQuery('#consoleActivity').append(html);
298 if(/Scan complete\./i.test(item.msg)){
299 this.loadIssues();
300 }
301 }
302 },
303 processSummaryLine: function(item){
304 if(item.msg.indexOf('SUM_START:') != -1){
305 var msg = item.msg.replace('SUM_START:', '');
306 jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult"><div class="wfSummaryLoading"></div></div><div class="wfClear"></div>');
307 summaryUpdated = true;
308 } else if(item.msg.indexOf('SUM_ENDBAD') != -1){
309 var msg = item.msg.replace('SUM_ENDBAD:', '');
310 jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryBad').html('Problems found.');
311 summaryUpdated = true;
312 } else if(item.msg.indexOf('SUM_ENDFAILED') != -1){
313 var msg = item.msg.replace('SUM_ENDFAILED:', '');
314 jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryBad').html('Failed.');
315 summaryUpdated = true;
316 } else if(item.msg.indexOf('SUM_ENDOK') != -1){
317 var msg = item.msg.replace('SUM_ENDOK:', '');
318 jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryOK').html('Secure.');
319 summaryUpdated = true;
320 } else if(item.msg.indexOf('SUM_ENDSUCCESS') != -1){
321 var msg = item.msg.replace('SUM_ENDSUCCESS:', '');
322 jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryOK').html('Success.');
323 summaryUpdated = true;
324 } else if(item.msg.indexOf('SUM_ENDERR') != -1){
325 var msg = item.msg.replace('SUM_ENDERR:', '');
326 jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryErr').html('An error occurred.');
327 summaryUpdated = true;
328 } else if(item.msg.indexOf('SUM_DISABLED:') != -1){
329 var msg = item.msg.replace('SUM_DISABLED:', '');
330 jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult">Disabled [<a href="admin.php?page=WordfenceSecOpt">Visit Options to Enable</a>]</div><div class="wfClear"></div>');
331 summaryUpdated = true;
332 } else if(item.msg.indexOf('SUM_PAIDONLY:') != -1){
333 var msg = item.msg.replace('SUM_PAIDONLY:', '');
334 jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult"><a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">Paid Members Only</a></div><div class="wfClear"></div>');
335 summaryUpdated = true;
336 } else if(item.msg.indexOf('SUM_FINAL:') != -1){
337 var msg = item.msg.replace('SUM_FINAL:', '');
338 jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg wfSummaryFinal">' + msg + '</div><div class="wfSummaryResult wfSummaryOK">Scan Complete.</div><div class="wfClear"></div>');
339 } else if(item.msg.indexOf('SUM_PREP:') != -1){
340 var msg = item.msg.replace('SUM_PREP:', '');
341 jQuery('#consoleSummary').empty().html('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult" id="wfStartingScan"><div class="wfSummaryLoading"></div></div><div class="wfClear"></div>');
342 } else if(item.msg.indexOf('SUM_KILLED:') != -1){
343 var msg = item.msg.replace('SUM_KILLED:', '');
344 jQuery('#consoleSummary').empty().html('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult wfSummaryOK">Scan Complete.</div><div class="wfClear"></div>');
345 }
346 },
347 processActQueueItem: function(){
348 var item = this.activityQueue.shift();
349 if(item){
350 jQuery('#consoleActivity').append('<div class="wfActivityLine wf' + item.type + '">[' + item.date + ']&nbsp;' + item.msg + '</div>');
351 this.totalActAdded++;
352 if(this.totalActAdded > this.maxActivityLogItems){
353 jQuery('#consoleActivity div:first').remove();
354 this.totalActAdded--;
355 }
356 if(item.msg == 'Scan complete.'){
357 this.loadIssues();
358 }
359 }
360 },
361 updateTicker: function(forceUpdate){
362 if( (! forceUpdate) && this.tickerUpdatePending){
363 return;
364 }
365 this.tickerUpdatePending = true;
366 var self = this;
367 var alsoGet = '';
368 var otherParams = '';
369 if(this.mode == 'activity' && /^(?:404|hit|human|ruser|gCrawler|crawler|loginLogout)$/.test(this.activityMode)){
370 alsoGet = 'logList_' + this.activityMode;
371 otherParams = this.newestActivityTime;
372 }
373 this.ajax('wordfence_ticker', {
374 alsoGet: alsoGet,
375 otherParams: otherParams
376 }, function(res){ self.handleTickerReturn(res); }, function(){ self.tickerUpdatePending = false; }, true);
377 },
378 handleTickerReturn: function(res){
379 this.tickerUpdatePending = false;
380 var newMsg = "";
381 var oldMsg = jQuery('#wfLiveStatus').text();
382 if( res.msg ){
383 newMsg = res.msg;
384 } else {
385 newMsg = "Idle";
386 }
387 if(newMsg && newMsg != oldMsg){
388 jQuery('#wfLiveStatus').hide().html(newMsg).fadeIn(200);
389 }
390
391 if(this.mode == 'activity'){
392 if(res.alsoGet != 'logList_' + this.activityMode){ return; } //user switched panels since ajax request started
393 if(res.events.length > 0){
394 this.newestActivityTime = res.events[0]['ctime'];
395 }
396 var haveEvents = false;
397 if(jQuery('#wfActivity_' + this.activityMode + ' .wfActEvent').length > 0){
398 haveEvents = true;
399 }
400 if(res.events.length > 0){
401 if(! haveEvents){
402 jQuery('#wfActivity_' + this.activityMode).empty();
403 }
404 for(i = res.events.length - 1; i >= 0; i--){
405 var elemID = '#wfActEvent_' + res.events[i].id;
406 if(jQuery(elemID).length < 1){
407 res.events[i]['activityMode'] = this.activityMode;
408 var newElem;
409 if(this.activityMode == 'loginLogout'){
410 newElem = jQuery('#wfLoginLogoutEventTmpl').tmpl(res.events[i]);
411 } else {
412 newElem = jQuery('#wfHitsEventTmpl').tmpl(res.events[i]);
413 }
414 jQuery(newElem).find('.wfTimeAgo').data('wfctime', res.events[i].ctime);
415 newElem.prependTo('#wfActivity_' + this.activityMode).fadeIn();
416 }
417 }
418 this.reverseLookupIPs();
419 } else {
420 if(! haveEvents){
421 jQuery('#wfActivity_' + this.activityMode).html('<div>No events to report yet.</div>');
422 }
423 }
424 var self = this;
425 jQuery('.wfTimeAgo').each(function(idx, elem){
426 jQuery(elem).html(self.makeTimeAgo(res.serverTime - jQuery(elem).data('wfctime')) + ' ago');
427 });
428 }
429 },
430 reverseLookupIPs: function(){
431 var ips = [];
432 jQuery('.wfReverseLookup').each(function(idx, elem){
433 var txt = jQuery(elem).text();
434 if(/^\d+\.\d+\.\d+\.\d+$/.test(txt) && (! jQuery(elem).data('wfReverseDone'))){
435 jQuery(elem).data('wfReverseDone', true);
436 ips.push(jQuery(elem).text());
437 }
438 });
439 if(ips.length < 1){ return; }
440 var uni = {};
441 var uniqueIPs = [];
442 for(var i = 0; i < ips.length; i++){
443 if(! uni[ips[i]]){
444 uni[ips[i]] = true;
445 uniqueIPs.push(ips[i]);
446 }
447 }
448 this.ajax('wordfence_reverseLookup', {
449 ips: uniqueIPs.join(',')
450 },
451 function(res){
452 if(res.ok){
453 jQuery('.wfReverseLookup').each(function(idx, elem){
454 var txt = jQuery(elem).text();
455 for(ip in res.ips){
456 if(txt == ip){
457 if(res.ips[ip]){
458 jQuery(elem).html('<strong>Hostname:</strong>&nbsp;' + res.ips[ip]);
459 } else {
460 jQuery(elem).html('');
461 }
462 }
463 }
464 });
465 }
466 }, false, false);
467 },
468 killScan: function(){
469 var self = this;
470 this.ajax('wordfence_killScan', {}, function(res){
471 if(res.ok){
472 self.colorbox('400px', "Kill requested", "A termination request has been sent to any running scans.");
473 } else {
474 self.colorbox('400px', "Kill failed", "We failed to send a termination request.");
475 }
476 });
477 },
478 startScan: function(){
479 var scanReqAnimation = setInterval(function(){
480 var str = jQuery('#wfStartScanButton1').prop('value');
481 ch = str.charAt(str.length - 1);
482 if(ch == '/'){ ch = '-'; }
483 else if(ch == '-'){ ch = '\\'; }
484 else if(ch == '\\'){ ch = '|'; }
485 else if(ch == '|'){ ch = '/'; }
486 else {ch = '/'; }
487 jQuery('#wfStartScanButton1,#wfStartScanButton2').prop('value', "Requesting a New Scan " + ch);
488 }, 100);
489 setTimeout(function(res){
490 clearInterval(scanReqAnimation);
491 jQuery('#wfStartScanButton1,#wfStartScanButton2').prop('value', "Start a Wordfence Scan");
492 }, 3000);
493 this.ajax('wordfence_scan', {}, function(res){ } );
494 },
495 loadIssues: function(callback){
496 if(this.mode != 'scan'){
497 return;
498 }
499 var self = this;
500 this.ajax('wordfence_loadIssues', { }, function(res){
501 self.displayIssues(res, callback);
502 });
503 },
504 sev2num: function(str){
505 if(/wfProbSev1/.test(str)){
506 return 1;
507 } else if(/wfProbSev2/.test(str)){
508 return 2;
509 } else {
510 return 0;
511 }
512 },
513 displayIssues: function(res, callback){
514 var self = this;
515 res.summary['lastScanCompleted'] = res['lastScanCompleted'];
516 jQuery('.wfIssuesContainer').hide();
517 for(issueStatus in res.issuesLists){
518 var containerID = 'wfIssues_dataTable_' + issueStatus;
519 var tableID = 'wfIssuesTable_' + issueStatus;
520 if(jQuery('#' + containerID).length < 1){
521 //Invalid issue status
522 continue;
523 }
524 if(res.issuesLists[issueStatus].length < 1){
525 if(issueStatus == 'new'){
526 if(res.lastScanCompleted == 'ok'){
527 jQuery('#' + containerID).html('<p style="font-size: 20px; color: #0A0;">Congratulations! You have no security issues on your site.</p>');
528 } else if(res['lastScanCompleted']){
529 //jQuery('#' + containerID).html('<p style="font-size: 12px; color: #A00;">The latest scan failed: ' + res.lastScanCompleted + '</p>');
530 } else {
531 jQuery('#' + containerID).html();
532 }
533
534 } else {
535 jQuery('#' + containerID).html('<p>There are currently <strong>no issues</strong> being ignored on this site.</p>');
536 }
537 continue;
538 }
539 jQuery('#' + containerID).html('<table cellpadding="0" cellspacing="0" border="0" class="display" id="' + tableID + '"></table>');
540
541 jQuery.fn.dataTableExt.oSort['severity-asc'] = function(y,x){ x = WFAD.sev2num(x); y = WFAD.sev2num(y); if(x < y){ return 1; } if(x > y){ return -1; } return 0; };
542 jQuery.fn.dataTableExt.oSort['severity-desc'] = function(y,x){ x = WFAD.sev2num(x); y = WFAD.sev2num(y); if(x > y){ return 1; } if(x < y){ return -1; } return 0; };
543
544 jQuery('#' + tableID).dataTable({
545 "bFilter": false,
546 "bInfo": false,
547 "bPaginate": false,
548 "bLengthChange": false,
549 "bAutoWidth": false,
550 "aaData": res.issuesLists[issueStatus],
551 "aoColumns": [
552 {
553 "sTitle": '<div class="th_wrapp">Severity</div>',
554 "sWidth": '128px',
555 "sClass": "center",
556 "sType": 'severity',
557 "fnRender": function(obj) {
558 var cls = "";
559 cls = 'wfProbSev' + obj.aData.severity;
560 return '<span class="' + cls + '"></span>';
561 }
562 },
563 {
564 "sTitle": '<div class="th_wrapp">Issue</div>',
565 "bSortable": false,
566 "sWidth": '400px',
567 "sType": 'html',
568 fnRender: function(obj){
569 var tmplName = 'issueTmpl_' + obj.aData.type;
570 return jQuery('#' + tmplName).tmpl(obj.aData).html();
571 }
572 }
573 ]
574 });
575 }
576 if(callback){
577 jQuery('#wfIssues_' + this.visibleIssuesPanel).fadeIn(500, function(){ callback(); });
578 } else {
579 jQuery('#wfIssues_' + this.visibleIssuesPanel).fadeIn(500);
580 }
581 return true;
582 },
583 ajax: function(action, data, cb, cbErr, noLoading){
584 if(typeof(data) == 'string'){
585 if(data.length > 0){
586 data += '&';
587 }
588 data += 'action=' + action + '&nonce=' + this.nonce;
589 } else if(typeof(data) == 'object'){
590 data['action'] = action;
591 data['nonce'] = this.nonce;
592 }
593 if(! cbErr){
594 cbErr = function(){};
595 }
596 var self = this;
597 if(! noLoading){
598 this.showLoading();
599 }
600 jQuery.ajax({
601 type: 'POST',
602 url: WordfenceAdminVars.ajaxURL,
603 dataType: "json",
604 data: data,
605 success: function(json){
606 if(! noLoading){
607 self.removeLoading();
608 }
609 if(json && json.nonce){
610 self.nonce = json.nonce;
611 }
612 if(json && json.errorMsg){
613 self.colorbox('400px', 'An error occurred', json.errorMsg);
614 }
615 cb(json);
616 },
617 error: function(){
618 if(! noLoading){
619 self.removeLoading();
620 }
621 cbErr();
622 }
623 });
624 },
625 colorbox: function(width, heading, body){
626 this.colorboxQueue.push([width, heading, body]);
627 this.colorboxServiceQueue();
628 },
629 colorboxServiceQueue: function(){
630 if(this.colorboxIsOpen){ return; }
631 if(this.colorboxQueue.length < 1){ return; }
632 var elem = this.colorboxQueue.shift();
633 this.colorboxOpen(elem[0], elem[1], elem[2]);
634 },
635 colorboxOpen: function(width, heading, body){
636 this.colorboxIsOpen = true;
637 jQuery.colorbox({ width: width, html: "<h3>" + heading + "</h3><p>" + body + "</p>"});
638 },
639 scanRunningMsg: function(){ this.colorbox('400px', "A scan is running", "A scan is currently in progress. Please wait until it finishes before starting another scan."); },
640 errorMsg: function(msg){ this.colorbox('400px', "An error occurred:", msg); },
641 deleteFile: function(issueID){
642 var self = this;
643 this.ajax('wordfence_deleteFile', {
644 issueID: issueID
645 }, function(res){ self.doneDeleteFile(res); });
646 },
647 doneDeleteFile: function(res){
648 var cb = false;
649 var self = this;
650 if(res.ok){
651 this.loadIssues(function(){ self.colorbox('400px', "Success deleting file", "The file " + res.file + " was successfully deleted."); });
652 } else if(res.cerrorMsg){
653 this.loadIssues(function(){ self.colorbox('400px', 'An error occurred', res.cerrorMsg); });
654 }
655 },
656 restoreFile: function(issueID){
657 var self = this;
658 this.ajax('wordfence_restoreFile', {
659 issueID: issueID
660 }, function(res){ self.doneRestoreFile(res); });
661 },
662 doneRestoreFile: function(res){
663 var self = this;
664 if(res.ok){
665 this.loadIssues(function(){ self.colorbox("400px", "File restored OK", "The file " + res.file + " was restored succesfully."); });
666 } else if(res.cerrorMsg){
667 this.loadIssues(function(){ self.colorbox('400px', 'An error occurred', res.cerrorMsg); });
668 }
669 },
670 deleteIssue: function(id){
671 var self = this;
672 this.ajax('wordfence_deleteIssue', { id: id }, function(res){
673 self.loadIssues();
674 });
675 },
676 updateIssueStatus: function(id, st){
677 var self = this;
678 this.ajax('wordfence_updateIssueStatus', { id: id, 'status': st }, function(res){
679 if(res.ok){
680 self.loadIssues();
681 }
682 });
683 },
684 updateAllIssues: function(op){ // deleteIgnored, deleteNew, ignoreAllNew
685 var head = "Please confirm";
686 if(op == 'deleteIgnored'){
687 body = "You have chosen to remove all ignored issues. Once these issues are removed they will be re-scanned by Wordfence and if they have not been fixed, they will appear in the 'new issues' list. Are you sure you want to do this?";
688 } else if(op == 'deleteNew'){
689 body = "You have chosen to mark all new issues as fixed. If you have not really fixed these issues, they will reappear in the new issues list on the next scan. If you have not fixed them and want them excluded from scans you should choose to 'ignore' them instead. Are you sure you want to mark all new issues as fixed?";
690 } else if(op == 'ignoreAllNew'){
691 body = "You have chosen to ignore all new issues. That means they will be excluded from future scans. You should only do this if you're sure all new issues are not a problem. Are you sure you want to ignore all new issues?";
692 } else {
693 return;
694 }
695 this.colorbox('450px', head, body + '<br /><br /><center><input type="button" name="but1" value="Cancel" onclick="jQuery.colorbox.close();" />&nbsp;&nbsp;&nbsp;<input type="button" name="but2" value="Yes I\'m sure" onclick="jQuery.colorbox.close(); WFAD.confirmUpdateAllIssues(\'' + op + '\');" /><br />');
696 },
697 confirmUpdateAllIssues: function(op){
698 var self = this;
699 this.ajax('wordfence_updateAllIssues', { op: op }, function(res){ self.loadIssues(); });
700 },
701 es: function(val){
702 if(val){
703 return val;
704 } else {
705 return "";
706 }
707 },
708 noQuotes: function(str){
709 return str.replace(/"/g,'&#34;').replace(/\'/g, '&#145;');
710 },
711 commify: function(num){
712 return ("" + num).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
713 },
714 switchToLiveTab: function(elem){
715 jQuery('.wfTab1').removeClass('selected');
716 jQuery(elem).addClass('selected');
717 jQuery('.wfDataPanel').hide();
718 var self = this;
719 jQuery('#wfActivity').fadeIn(function(){ self.completeLiveTabSwitch(); });
720 },
721 completeLiveTabSwitch: function(){
722 this.ajax('wordfence_loadActivityLog', {}, function(res){
723 var html = '<a href="#" class="wfALogMailLink" onclick="WFAD.emailActivityLog(); return false;"></a><a href="#" class="wfALogReloadLink" onclick="WFAD.reloadActivityData(); return false;"></a>';
724 if(res.events && res.events.length > 0){
725 jQuery('#wfActivity').empty();
726 for(var i = 0; i < res.events.length; i++){
727 var timeTaken = '0.0000';
728 if(res.events[i + 1]){
729 timeTaken = (res.events[i].ctime - res.events[i + 1].ctime).toFixed(4);
730 }
731 var red = "";
732 if(res.events[i].type == 'error'){
733 red = ' class="wfWarn" ';
734 }
735 html += '<div ' + red + 'class="wfALogEntry"><span ' + red + 'class="wfALogTime">[' + res.events[i].type + '&nbsp;:&nbsp;' + timeTaken + '&nbsp;:&nbsp;' + res.events[i].timeAgo + ' ago]</span>&nbsp;' + res.events[i].msg + "</div>";
736 }
737 jQuery('#wfActivity').html(html);
738 } else {
739 jQuery('#wfActivity').html("<p>&nbsp;&nbsp;No activity to report yet. Please complete your first scan.</p>");
740 }
741 });
742 },
743 emailActivityLog: function(){
744 this.colorbox('400px', 'Email Wordfence Activity Log', "Enter the email address you would like to send the Wordfence activity log to. Note that the activity log may contain thousands of lines of data. This log is usually only sent to a member of the Wordfence support team. It also contains your PHP configuration from the phpinfo() function for diagnostic data.<br /><br /><input type='text' value='support@wordfence.com' size='20' id='wfALogRecip' /><input type='button' value='Send' onclick=\"WFAD.completeEmailActivityLog();\" /><input type='button' value='Cancel' onclick='jQuery.colorbox.close();' /><br /><br />");
745 },
746 completeEmailActivityLog: function(){
747 jQuery.colorbox.close();
748 var email = jQuery('#wfALogRecip').val();
749 if(! /^[^@]+@[^@]+$/.test(email)){
750 alert("Please enter a valid email address.");
751 return;
752 }
753 var self = this;
754 this.ajax('wordfence_sendActivityLog', { email: jQuery('#wfALogRecip').val() }, function(res){
755 if(res.ok){
756 self.colorbox('400px', 'Activity Log Sent', "Your Wordfence activity log was sent to " + email + "<br /><br /><input type='button' value='Close' onclick='jQuery.colorbox.close();' /><br /><br />");
757 }
758 });
759 },
760 reloadActivityData: function(){
761 jQuery('#wfActivity').html('<div class="wfLoadingWhite32"></div>'); //&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />
762 this.completeLiveTabSwitch();
763 },
764 switchToSummaryTab: function(elem){
765 jQuery('.wfTab1').removeClass('selected');
766 jQuery(elem).addClass('selected');
767 jQuery('.wfDataPanel').hide();
768 jQuery('#wfSummaryTables').fadeIn();
769 },
770 switchIssuesTab: function(elem, type){
771 jQuery('.wfTab2').removeClass('selected');
772 jQuery('.wfIssuesContainer').hide();
773 jQuery(elem).addClass('selected');
774 this.visibleIssuesPanel = type;
775 jQuery('#wfIssues_' + type).fadeIn();
776 },
777 switchTab: function(tabElement, tabClass, contentClass, selectedContentID, callback){
778 jQuery('.' + tabClass).removeClass('selected');
779 jQuery(tabElement).addClass('selected');
780 jQuery('.' + contentClass).hide().html('<div class="wfLoadingWhite32"></div>');
781 var func = function(){};
782 if(callback){
783 func = function(){ callback(); };
784 }
785 jQuery('#' + selectedContentID).fadeIn(func);
786 },
787 activityTabChanged: function(){
788 var mode = jQuery('.wfDataPanel:visible')[0].id.replace('wfActivity_','');
789 if(! mode){ return; }
790 this.activityMode = mode;
791 this.reloadActivities();
792 },
793 reloadActivities: function(){
794 jQuery('#wfActivity_' + this.activityMode).html('<div class="wfLoadingWhite32"></div>');
795 this.newestActivityTime = 0;
796 this.updateTicker(true);
797 },
798 staticTabChanged: function(){
799 var mode = jQuery('.wfDataPanel:visible')[0].id.replace('wfActivity_','');
800 if(! mode){ return; }
801 this.activityMode = mode;
802
803 var self = this;
804 this.ajax('wordfence_loadStaticPanel', {
805 mode: this.activityMode
806 }, function(res){
807 self.completeLoadStaticPanel(res);
808 });
809 },
810 completeLoadStaticPanel: function(res){
811 var contentElem = '#wfActivity_' + this.activityMode;
812 jQuery(contentElem).empty();
813 if(res.results && res.results.length > 0){
814 var tmpl;
815 if(this.activityMode == 'topScanners' || this.activityMode == 'topLeechers'){
816 tmpl = '#wfLeechersTmpl';
817 } else if(this.activityMode == 'blockedIPs'){
818 tmpl = '#wfBlockedIPsTmpl';
819 } else if(this.activityMode == 'lockedOutIPs'){
820 tmpl = '#wfLockedOutIPsTmpl';
821 } else if(this.activityMode == 'throttledIPs'){
822 tmpl = '#wfThrottledIPsTmpl';
823 } else { return; }
824 jQuery(tmpl).tmpl(res).prependTo(contentElem);
825 this.reverseLookupIPs();
826 } else {
827 if(this.activityMode == 'topScanners' || this.activityMode == 'topLeechers'){
828 jQuery(contentElem).html("No site hits have been logged yet. Check back soon.");
829 } else if(this.activityMode == 'blockedIPs'){
830 jQuery(contentElem).html("No IP addresses have been blocked yet. If you manually block an IP address or if Wordfence automatically blocks one, it will appear here.");
831 } else if(this.activityMode == 'lockedOutIPs'){
832 jQuery(contentElem).html("No IP addresses have been locked out from signing in or using the password recovery system.");
833 } else if(this.activityMode == 'throttledIPs'){
834 jQuery(contentElem).html("No IP addresses have been throttled yet. If an IP address accesses the site too quickly and breaks one of the Wordfence rules, it will appear here.");
835 } else { return; }
836 }
837 },
838 ucfirst: function(str){
839 str = "" + str;
840 return str.charAt(0).toUpperCase() + str.slice(1);
841 },
842 makeIPTrafLink: function(IP){
843 return WordfenceAdminVars.siteBaseURL + '?_wfsf=IPTraf&nonce=' + this.nonce + '&IP=' + encodeURIComponent(IP);
844 },
845 makeDiffLink: function(dat){
846 return WordfenceAdminVars.siteBaseURL + '?_wfsf=diff&nonce=' + this.nonce +
847 '&file=' + encodeURIComponent(this.es(dat['file'])) +
848 '&cType=' + encodeURIComponent(this.es(dat['cType'])) +
849 '&cKey=' + encodeURIComponent(this.es(dat['cKey'])) +
850 '&cName=' + encodeURIComponent(this.es(dat['cName'])) +
851 '&cVersion=' + encodeURIComponent(this.es(dat['cVersion']));
852 },
853 makeViewFileLink: function(file){
854 return WordfenceAdminVars.siteBaseURL + '?_wfsf=view&nonce=' + this.nonce + '&file=' + encodeURIComponent(file);
855 },
856 makeTimeAgo: function(t){
857 var months = Math.floor(t / (86400 * 30));
858 var days = Math.floor(t / 86400);
859 var hours = Math.floor(t / 3600);
860 var minutes = Math.floor(t / 60);
861 if(months > 0){
862 days -= months * 30;
863 return this.pluralize(months, 'month', days, 'day');
864 } else if(days > 0){
865 hours -= days * 24;
866 return this.pluralize(days, 'day', hours, 'hour');
867 } else if(hours > 0) {
868 minutes -= hours * 60;
869 return this.pluralize(hours, 'hour', minutes, 'min');
870 } else if(minutes > 0) {
871 //t -= minutes * 60;
872 return this.pluralize(minutes, 'minute');
873 } else {
874 return Math.round(t) + " seconds";
875 }
876 },
877 pluralize: function(m1, t1, m2, t2){
878 if(m1 != 1) {
879 t1 = t1 + 's';
880 }
881 if(m2 != 1) {
882 t2 = t2 + 's';
883 }
884 if(m1 && m2){
885 return m1 + ' ' + t1 + ' ' + m2 + ' ' + t2;
886 } else {
887 return m1 + ' ' + t1;
888 }
889 },
890 calcRangeTotal: function(){
891 var range = jQuery('#ipRange').val();
892 if(! range){ return; }
893 range = range.replace(/ /g, '');
894 if(range && /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s*\-\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(range)){
895 var ips = range.split('-');
896 var total = this.inet_aton(ips[1]) - this.inet_aton(ips[0]) + 1;
897 if(total < 1){
898 jQuery('#wfShowRangeTotal').html("<span style=\"color: #F00;\">Invalid. Starting IP is greater than ending IP.</span>");
899 return;
900 }
901 jQuery('#wfShowRangeTotal').html("<span style=\"color: #0A0;\">Valid: " + total + " addresses in range.</span>");
902 } else {
903 jQuery('#wfShowRangeTotal').empty();
904 }
905 },
906 loadBlockRanges: function(){
907 var self = this;
908 this.ajax('wordfence_loadBlockRanges', {}, function(res){ self.completeLoadBlockRanges(res); });
909
910 },
911 completeLoadBlockRanges: function(res){
912 jQuery('#currentBlocks').empty();
913 if(res.results && res.results.length > 0){
914 jQuery('#wfBlockedRangesTmpl').tmpl(res).prependTo('#currentBlocks');
915 } else {
916 jQuery('#currentBlocks').html("You have not blocked any IP ranges or other patterns yet.");
917 }
918 },
919 whois: function(val){
920 val = val.replace(' ','');
921 if( ! /\w+/.test(val)){
922 this.colorbox('300px', "Enter a valid IP or domain", "Please enter a valid IP address or domain name for your whois lookup.");
923 return;
924 }
925 var self = this;
926 jQuery('#whoisbutton').attr('disabled', 'disabled');
927 jQuery('#whoisbutton').attr('value', 'Loading...');
928 this.ajax('wordfence_whois', {
929 val: val
930 }, function(res){
931 jQuery('#whoisbutton').removeAttr('disabled');
932 jQuery('#whoisbutton').attr('value', 'Look up IP or Domain');
933 if(res.ok){
934 self.completeWhois(res);
935 }
936 });
937 },
938 completeWhois: function(res){
939 if(res.ok && res.result && res.result.rawdata && res.result.rawdata.length > 0){
940 var rawhtml = "";
941 for(var i = 0; i < res.result.rawdata.length; i++){
942 res.result.rawdata[i] = res.result.rawdata[i].replace(/([^\s\t\r\n:;]+@[^\s\t\r\n:;\.]+\.[^\s\t\r\n:;]+)/, "<a href=\"mailto:$1\">$1<\/a>");
943 res.result.rawdata[i] = res.result.rawdata[i].replace(/(https?:\/\/[^\/]+[^\s\r\n\t]+)/, "<a target=\"_blank\" href=\"$1\">$1<\/a>");
944 var redStyle = "";
945 if(this.getQueryParam('wfnetworkblock')){
946 redStyle = " style=\"color: #F00;\"";
947 }
948 var self = this;
949 function wfm21(str, ipRange, offset, totalStr){
950 var ips = ipRange.split(/\s*\-\s*/);
951 var ip1num = self.inet_aton(ips[0]);
952 var ip2num = self.inet_aton(ips[1]);
953 var totalIPs = ip2num - ip1num + 1;
954 return "<a href=\"admin.php?page=WordfenceRangeBlocking&wfBlockRange=" + ipRange + "\"" + redStyle + ">" + ipRange + " [<strong>" + totalIPs + "</strong> addresses in this network. Click to block this network]<\/a>";
955 }
956
957 res.result.rawdata[i] = res.result.rawdata[i].replace(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} - \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/, wfm21);
958 rawhtml += res.result.rawdata[i] + "<br />";
959 }
960 jQuery('#wfrawhtml').html(rawhtml);
961 } else {
962 jQuery('#wfrawhtml').html('<span style="color: #F00;">Sorry, but no data for that IP or domain was found.</span>');
963 }
964 },
965 blockIPUARange: function(ipRange, uaRange, reason){
966 if(! /\w+/.test(reason)){
967 this.colorbox('300px', "Please specify a reason", "You forgot to include a reason you're blocking this IP range. We ask you to include this for your own record keeping.");
968 return;
969 }
970 ipRange = ipRange.replace(/ /g, '');
971 if(ipRange){
972 if(! /^\d+\.\d+\.\d+\.\d+\-\d+\.\d+\.\d+\.\d+$/.test(ipRange)){
973 this.colorbox('300px', 'Specify a valid IP range', "Please specify a valid IP address range in the form of \"1.2.3.4 - 1.2.3.5\" without quotes. Make sure the dash between the IP addresses in a normal dash (a minus sign on your keyboard) and not another character that looks like a dash.");
974 return;
975 }
976 }
977 if( ! (/\w+/.test(ipRange) || /\w+/.test(uaRange))){
978 this.colorbox('300px', 'Specify an IP range or Browser pattern', "Please specify either an IP address range or a web browser pattern to match.");
979 return;
980 }
981 var self = this;
982 this.ajax('wordfence_blockIPUARange', {
983 ipRange: ipRange,
984 uaRange: uaRange,
985 reason: reason
986 }, function(res){
987 if(res.ok){
988 self.loadBlockRanges();
989 return;
990 }
991 });
992 },
993 unblockRange: function(id){
994 var self = this;
995 this.ajax('wordfence_unblockRange', {
996 id: id
997 }, function(res){
998 self.loadBlockRanges();
999 });
1000 },
1001 blockIP: function(IP, reason){
1002 var self = this;
1003 this.ajax('wordfence_blockIP', {
1004 IP: IP,
1005 reason: reason
1006 }, function(res){
1007 if(res.errorMsg){
1008 return;
1009 } else {
1010 self.reloadActivities();
1011 }
1012 });
1013 },
1014 blockIPTwo: function(IP, reason, perm){
1015 var self = this;
1016 this.ajax('wordfence_blockIP', {
1017 IP: IP,
1018 reason: reason,
1019 perm: (perm ? '1' : '0')
1020 }, function(res){
1021 if(res.errorMsg){
1022 return;
1023 } else {
1024 self.staticTabChanged();
1025 }
1026 });
1027 },
1028 unlockOutIP: function(IP){
1029 var self = this;
1030 this.ajax('wordfence_unlockOutIP', {
1031 IP: IP
1032 }, function(res){ self.staticTabChanged(); });
1033 },
1034 unblockIP: function(IP){
1035 var self = this;
1036 this.ajax('wordfence_unblockIP', {
1037 IP: IP
1038 }, function(res){
1039 self.reloadActivities();
1040 });
1041 },
1042 unblockIPTwo: function(IP){
1043 var self = this;
1044 this.ajax('wordfence_unblockIP', {
1045 IP: IP
1046 }, function(res){
1047 self.staticTabChanged();
1048 });
1049 },
1050 permBlockIP: function(IP){
1051 var self = this;
1052 this.ajax('wordfence_permBlockIP', {
1053 IP: IP
1054 }, function(res){ self.staticTabChanged(); });
1055 },
1056 makeElemID: function(){
1057 return 'wfElemGen' + this.elementGeneratorIter++;
1058 },
1059 pulse: function(sel){
1060 jQuery(sel).fadeIn(function(){
1061 setTimeout(function(){ jQuery(sel).fadeOut(); }, 2000);
1062 });
1063 },
1064 saveConfig: function(){
1065 var qstr = jQuery('#wfConfigForm').serialize();
1066 var self = this;
1067 jQuery('.wfSavedMsg').hide();
1068 jQuery('.wfAjax24').show();
1069 this.ajax('wordfence_saveConfig', qstr, function(res){
1070 jQuery('.wfAjax24').hide();
1071 if(res.ok){
1072 if(res['paidKeyMsg']){
1073 self.colorbox('400px', "Congratulations! You have been upgraded to Premium Scanning.", "You have upgraded to a Premium API key. Once this page reloads, you can choose which premium scanning options you would like to enable and then click save. Click the button below to reload this page now.<br /><br /><center><input type='button' name='wfReload' value='Reload page and enable Premium options' onclick='window.location.reload(true);' /></center>");
1074 return;
1075 } else if(res['reload'] == 'reload' || WFAD.reloadConfigPage){
1076 self.colorbox('400px', "Please reload this page", "You selected a config option that requires a page reload. Click the button below to reload this page to update the menu.<br /><br /><center><input type='button' name='wfReload' value='Reload page' onclick='window.location.reload(true);' /></center>");
1077 return;
1078 } else {
1079 self.pulse('.wfSavedMsg');
1080 }
1081 } else if(res.errorMsg){
1082 return;
1083 } else {
1084 self.colorbox('400px', 'An error occurred', 'We encountered an error trying to save your changes.');
1085 }
1086 });
1087 },
1088 changeSecurityLevel: function(){
1089 var level = jQuery('#securityLevel').val();
1090 for(var k in WFSLevels[level].checkboxes){
1091 if(k != 'liveTraf_ignorePublishers'){
1092 jQuery('#' + k).prop("checked", WFSLevels[level].checkboxes[k]);
1093 }
1094 }
1095 for(var k in WFSLevels[level].otherParams){
1096 if(! /^(?:apiKey|securityLevel|alertEmails|liveTraf_ignoreUsers|liveTraf_ignoreIPs|liveTraf_ignoreUA|liveTraf_hitsMaxSize|maxMem|maxExecutionTime|actUpdateInterval)$/.test(k)){
1097 jQuery('#' + k).val(WFSLevels[level].otherParams[k]);
1098 }
1099 }
1100 },
1101 clearAllBlocked: function(op){
1102 if(op == 'blocked'){
1103 body = "Are you sure you want to clear all blocked IP addresses and allow visitors from those addresses to access the site again?";
1104 } else if(op == 'locked'){
1105 body = "Are you sure you want to clear all locked IP addresses and allow visitors from those addresses to sign in again?";
1106 } else {
1107 return;
1108 }
1109 this.colorbox('450px', "Please confirm", body +
1110 '<br /><br /><center><input type="button" name="but1" value="Cancel" onclick="jQuery.colorbox.close();" />&nbsp;&nbsp;&nbsp;' +
1111 '<input type="button" name="but2" value="Yes I\'m sure" onclick="jQuery.colorbox.close(); WFAD.confirmClearAllBlocked(\'' + op + '\');"><br />');
1112 },
1113 confirmClearAllBlocked: function(op){
1114 var self = this;
1115 this.ajax('wordfence_clearAllBlocked', { op: op }, function(res){
1116 self.staticTabChanged();
1117 });
1118 },
1119 setOwnCountry: function(code){
1120 this.ownCountry = (code + "").toUpperCase();
1121 },
1122 loadBlockedCountries: function(str){
1123 var codes = str.split(',');
1124 for(var i = 0; i < codes.length; i++){
1125 jQuery('#wfCountryCheckbox_' + codes[i]).prop('checked', true);
1126 }
1127 },
1128 saveCountryBlocking: function(){
1129 var action = jQuery('#wfBlockAction').val();
1130 var redirURL = jQuery('#wfRedirURL').val();
1131 var bypassRedirURL = jQuery('#wfBypassRedirURL').val();
1132 var bypassRedirDest = jQuery('#wfBypassRedirDest').val();
1133 var bypassViewURL = jQuery('#wfBypassViewURL').val();
1134
1135 if(action == 'redir' && (! /^https?:\/\/[^\/]+/i.test(redirURL))){
1136 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://");
1137 return;
1138 }
1139 if( bypassRedirURL || bypassRedirDest ){
1140 if(! (bypassRedirURL && bypassRedirDest)){
1141 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.");
1142 return;
1143 }
1144 if(bypassRedirURL == bypassRedirDest){
1145 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.");
1146 return;
1147 }
1148 }
1149 if(bypassRedirURL && (! /^(?:\/|http:\/\/)/.test(bypassRedirURL))){ this.invalidCountryURLMsg(bypassRedirURL); return; }
1150 if(bypassRedirDest && (! /^(?:\/|http:\/\/)/.test(bypassRedirDest))){ this.invalidCountryURLMsg(bypassRedirDest); return; }
1151 if(bypassViewURL && (! /^(?:\/|http:\/\/)/.test(bypassViewURL))){ this.invalidCountryURLMsg(bypassViewURL); return; }
1152
1153 var codesArr = [];
1154 var ownCountryBlocked = false;
1155 var self = this;
1156 jQuery('.wfCountryCheckbox').each(function(idx, elem){
1157 if(jQuery(elem).is(':checked')){
1158 var code = jQuery(elem).val();
1159 codesArr.push(code);
1160 if(code == self.ownCountry){
1161 ownCountryBlocked = true;
1162 }
1163 }
1164 });
1165 var codes = codesArr.join(',');
1166 this.countryCodesToSave = codes;
1167 if(ownCountryBlocked){
1168 this.colorbox('400px', "Please confirm blocking yourself", "You are about to block your own country. This could lead to you being locked out. Please make sure that your user profile on this machine has a current and valid email address and make sure you know what it is. That way if you are locked out, you can send yourself an unlock email. If you're sure you want to block your own country, click 'Confirm' below, otherwise click 'Cancel'.<br />" +
1169 '<input type="button" name="but1" value="Confirm" onclick="jQuery.colorbox.close(); WFAD.confirmSaveCountryBlocking();" />&nbsp;<input type="button" name="but1" value="Cancel" onclick="jQuery.colorbox.close();" />');
1170 } else {
1171 this.confirmSaveCountryBlocking();
1172 }
1173 },
1174 invalidCountryURLMsg: function(URL){
1175 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);
1176 return;
1177 },
1178 confirmSaveCountryBlocking: function(){
1179 var action = jQuery('#wfBlockAction').val();
1180 var redirURL = jQuery('#wfRedirURL').val();
1181 var loggedInBlocked = jQuery('#wfLoggedInBlocked').is(':checked') ? '1' : '0';
1182 var loginFormBlocked = jQuery('#wfLoginFormBlocked').is(':checked') ? '1' : '0';
1183 var bypassRedirURL = jQuery('#wfBypassRedirURL').val();
1184 var bypassRedirDest = jQuery('#wfBypassRedirDest').val();
1185 var bypassViewURL = jQuery('#wfBypassViewURL').val();
1186
1187 jQuery('.wfAjax24').show();
1188 var self = this;
1189 this.ajax('wordfence_saveCountryBlocking', {
1190 blockAction: action,
1191 redirURL: redirURL,
1192 loggedInBlocked: loggedInBlocked,
1193 loginFormBlocked: loginFormBlocked,
1194 bypassRedirURL: bypassRedirURL,
1195 bypassRedirDest: bypassRedirDest,
1196 bypassViewURL: bypassViewURL,
1197 codes: this.countryCodesToSave
1198 }, function(res){
1199 jQuery('.wfAjax24').hide();
1200 self.pulse('.wfSavedMsg');
1201 });
1202 },
1203 paidUsersOnly: function(msg){
1204 var pos = jQuery('#paidWrap').position();
1205 var width = jQuery('#paidWrap').width();
1206 var height = jQuery('#paidWrap').height();
1207 jQuery('<div style="position: absolute; left: ' + pos.left + 'px; top: ' + pos.top + 'px; background-color: #FFF; width: ' + width + 'px; height: ' + height + 'px;"><div class="paidInnerMsg">' + msg + ' <a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">Click here to upgrade and gain access to this feature.</div></div>').insertAfter('#paidWrap').fadeTo(10000, 0.7);
1208 },
1209 sched_modeChange: function(){
1210 var self = this;
1211 if(jQuery('#schedMode').val() == 'auto'){
1212 jQuery('.wfSchedCheckbox').attr('disabled', true);
1213 } else {
1214 jQuery('.wfSchedCheckbox').attr('disabled', false);
1215 }
1216 },
1217 sched_shortcut: function(mode){
1218 if(jQuery('#schedMode').val() == 'auto'){
1219 this.colorbox('400px', 'Change the scan mode', "You need to change the scan mode to manually scheduled scans if you want to select scan times.");
1220 return;
1221 }
1222 jQuery('.wfSchedCheckbox').prop('checked', false);
1223 if(this.schedStartHour === false){
1224 this.schedStartHour = Math.floor((Math.random()*24));
1225 } else {
1226 this.schedStartHour++;
1227 if(this.schedStartHour > 23){
1228 this.schedStartHour = 0;
1229 }
1230 }
1231 if(mode == 'onceDaily'){
1232 for(var i = 0; i <= 6; i++){
1233 jQuery('#wfSchedDay_' + i + '_' + this.schedStartHour).attr('checked', true);
1234 }
1235 } else if(mode == 'twiceDaily'){
1236 var secondHour = this.schedStartHour + 12;
1237 if(secondHour >= 24){ secondHour = secondHour - 24; }
1238 for(var i = 0; i <= 6; i++){
1239 jQuery('#wfSchedDay_' + i + '_' + this.schedStartHour).attr('checked', true);
1240 jQuery('#wfSchedDay_' + i + '_' + secondHour).attr('checked', true);
1241 }
1242 } else if(mode == 'oddDaysWE'){
1243 var startDay = Math.floor((Math.random()));
1244 jQuery('#wfSchedDay_1_' + this.schedStartHour).attr('checked', true);
1245 jQuery('#wfSchedDay_3_' + this.schedStartHour).attr('checked', true);
1246 jQuery('#wfSchedDay_5_' + this.schedStartHour).attr('checked', true);
1247 jQuery('#wfSchedDay_6_' + this.schedStartHour).attr('checked', true);
1248 jQuery('#wfSchedDay_0_' + this.schedStartHour).attr('checked', true);
1249 } else if(mode == 'weekends'){
1250 var startDay = Math.floor((Math.random()));
1251 jQuery('#wfSchedDay_6_' + this.schedStartHour).attr('checked', true);
1252 jQuery('#wfSchedDay_0_' + this.schedStartHour).attr('checked', true);
1253 } else if(mode == 'every6hours'){
1254 for(var i = 0; i <= 6; i++){
1255 for(var hour = this.schedStartHour; hour < this.schedStartHour + 24; hour = hour + 6){
1256 var displayHour = hour;
1257 if(displayHour >= 24){ displayHour = displayHour - 24; }
1258 jQuery('#wfSchedDay_' + i + '_' + displayHour).attr('checked', true);
1259 }
1260 }
1261 }
1262
1263 },
1264 sched_save: function(){
1265 var schedMode = jQuery('#schedMode').val();
1266 var schedule = [];
1267 for(var day = 0; day <= 6; day++){
1268 var hours = [];
1269 for(var hour = 0; hour <= 23; hour++){
1270 var elemID = '#wfSchedDay_' + day + '_' + hour;
1271 hours[hour] = jQuery(elemID).is(':checked') ? '1' : '0';
1272 }
1273 schedule[day] = hours.join(',');
1274 }
1275 scheduleTxt = schedule.join('|');
1276 var self = this;
1277 this.ajax('wordfence_saveScanSchedule', {
1278 schedMode: schedMode,
1279 schedTxt: scheduleTxt
1280 }, function(res){
1281 jQuery('#wfScanStartTime').html(res.nextStart);
1282 jQuery('.wfAjax24').hide();
1283 self.pulse('.wfSaveMsg');
1284 });
1285 },
1286 twoFacStatus: function(msg){
1287 jQuery('#wfTwoFacMsg').html(msg);
1288 jQuery('#wfTwoFacMsg').fadeIn(function(){
1289 setTimeout(function(){ jQuery('#wfTwoFacMsg').fadeOut(); }, 2000);
1290 });
1291 },
1292 addTwoFactor: function(username, phone){
1293 var self = this;
1294 this.ajax('wordfence_addTwoFactor', {
1295 username: username,
1296 phone: phone
1297 }, function(res){
1298 if(res.ok){
1299 self.twoFacStatus('User added! Check the user\'s phone to get the activation code.');
1300 jQuery('<div id="twoFacCont_' + res.userID + '">' + jQuery('#wfTwoFacUserTmpl').tmpl(res).html() + '</div>').prependTo(jQuery('#wfTwoFacUsers'));
1301 }
1302 });
1303 },
1304 twoFacActivate: function(userID, code){
1305 var self = this;
1306 this.ajax('wordfence_twoFacActivate', {
1307 userID: userID,
1308 code: code
1309 }, function(res){
1310 if(res.ok){
1311 jQuery('#twoFacCont_' + res.userID).html(
1312 jQuery('#wfTwoFacUserTmpl').tmpl(res)
1313 );
1314 self.twoFacStatus('Cellphone Sign-in activated for user.');
1315 }
1316 });
1317 },
1318 delTwoFac: function(userID){
1319 this.ajax('wordfence_twoFacDel', {
1320 userID: userID
1321 }, function(res){
1322 if(res.ok){
1323 jQuery('#twoFacCont_' + res.userID).fadeOut(function(){ jQuery(this).remove(); });
1324 }
1325 });
1326 },
1327 loadTwoFactor: function(){
1328 this.ajax('wordfence_loadTwoFactor', {}, function(res){
1329 if(res.users && res.users.length > 0){
1330 for(var i = 0; i < res.users.length; i++){
1331 jQuery('<div id="twoFacCont_' + res.users[i].userID + '">' +
1332 jQuery('#wfTwoFacUserTmpl').tmpl(res.users[i]).html() +
1333 + '</div>').appendTo(jQuery('#wfTwoFacUsers'));
1334 }
1335 }
1336 });
1337 },
1338 getQueryParam: function(name){
1339 name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
1340 var regexS = "[\\?&]" + name + "=([^&#]*)";
1341 var regex = new RegExp(regexS);
1342 var results = regex.exec(window.location.search);
1343 if(results == null){
1344 return "";
1345 } else {
1346 return decodeURIComponent(results[1].replace(/\+/g, " "));
1347 }
1348 },
1349 inet_aton: function(dot) {
1350 var d = dot.split('.');
1351 return ((((((+d[0])*256)+(+d[1]))*256)+(+d[2]))*256)+(+d[3]);
1352 },
1353 inet_ntoa: function(num){
1354 var d = num % 256;
1355 for(var i = 3; i > 0; i--) {
1356 num = Math.floor(num/256);
1357 d = num%256 + '.' + d;
1358 }
1359 return d;
1360 }
1361 };
1362 window['WFAD'] = window['wordfenceAdmin'];
1363 }
1364 jQuery(function(){
1365 wordfenceAdmin.init();
1366 });
1367