src/log_analyzer/js/analyzer.tableBuilder.js
var logLoaded = false;
var filesDataTable = null;
var numberItemsInFilter;
var data = "";
var new_data = "";
var filters = {};
function displayContents(xmlStr) {
if (logLoaded) {
//loading filters from files
new_json = "";
signature = xmlStr.substring(0, 16).replace(/\s/, '');
//if xmlStr is json file
if (signature.indexOf('":{"') >= 0)
new_json = JSON.parse(xmlStr);
else {
new_json = parseXMLstrToJSON(xmlStr);
}
getFilter(new_json);
} else {
//loading log from file
logLoaded = true;
var json = parseXMLstrToJSON(xmlStr);
if (json ==null) {
showProgress(false);
alert('Invalid xml file');
window.location.reload();
return;
}
data = getFileInfoArray(json);
buildTable(data);
tryDownloadWhitelist();
}
};
function parseWebsiteLog(fileDictDict) {
var fileInfoArrayArray = new Array;
for(var fileDictName in fileDictDict) {
var fileInfoArray = new Array;
var fileDict = fileDictDict[fileDictName];
fileInfoArray.push(fileDict['_detected']);
fileInfoArray.push(fileDict['path']);
fileInfoArray.push(fileDict['size']);
fileInfoArray.push(fileDict.ctime);
fileInfoArray.push(fileDict.mtime);
fileInfoArray.push(fileDict['owner']);
fileInfoArray.push(fileDict['group']);
fileInfoArray.push(fileDict['access']);
if (!fileDict._pos) fileDict._pos = '0';
if (!fileDict.md5) fileDict.md5 = '';
if (!fileDict.path) fileDict.path = '';
extraData = {'md5': fileDict.md5, 'pos': fileDict._pos, 'path': fileDict.path}
if (fileDict._snippet) {
extraData['snippet'] = normalizeSnippet(atob(fileDict._snippet));
} else {
extraData['snippet'] = '-';
}
fileInfoArray.push(extraData);
fileInfoArray.push(fileDict.md5);
fileInfoArrayArray.push(fileInfoArray);
}
return fileInfoArrayArray;
}
function normalizeSnippet(str) {
return str.replace(/@_MARKER_@/gi, "<font color=#FF00FF><b>|</b></font>");
}
function parseWhitelist(fileDictDict) {
whitelist = {};
for(var fileDictName in fileDictDict) {
fileDict = fileDictDict[fileDictName];
if (fileDict.md5 && fileDict.md5.length > 1) {
whitelist[fileDict.md5] = fileDict.path;
}
}
console.log(Object.keys(whitelist).length + ' items in filter');
return whitelist;
}
var cmsDictList;
function getFileInfoArray(json) {
var fileDictDict;
if (json.hasOwnProperty('website_info')) {
cmsDictList = json.website_info.cms_list;
buildEnvTable(json.website_info.server_environment);
//website log
fileDictDict = json.website_info.files.file;
return parseWebsiteLog(fileDictDict);
}
}
function getFilter(json) {
if (json.hasOwnProperty('website_info')) {
//another log
log_name = 'websitelog';
try {
scan_date = json.website_info.server_environment.time.split(' ')[0].replace(/\./g,'-');
host_name = json.website_info.server_environment.http_host;
log_name = localization.locale_dict['TableScreen.Log'] + ': ' + host_name + ' ' + scan_date;
} catch (ex) {
console.log(ex);
}
var website_log_filter = parseWhitelist(json.website_info.files.file);
applyFilter(log_name, website_log_filter);
return true;
} else if (json.hasOwnProperty('whitelist')) {
//whitelist file
var whitelist_name = json.whitelist.meta.name + "_" + json.whitelist.meta.version;
console.log('Whitelist ' + whitelist_name + ' was loaded.');
var whitelist_filter = parseWhitelist(json.whitelist.files);
applyFilter(localization.locale_dict['TableScreen.Whitelist'] + ': ' + whitelist_name, whitelist_filter)
return true;
}
}
function downloadWhitelist(cms_name, cms_version) {
//FIXME
url = "http://manul.ml/downloads/get_wl.php?name=" + cms_name.toLowerCase() + "&version=" + cms_version + "&format=json";
console.log('Fetching whitelist from ' + url);
$.ajax({ type: "GET",
url: url,
async: false,
success : function(text)
{
whitelist_json = JSON.parse(text);
getFilter(whitelist_json);
console.log('Whitelist for ' + cms_name + ' ' + cms_version + ' was downloaded');
}
});
}
function tryDownloadWhitelist() {
for(var index in cmsDictList) {
cms = cmsDictList[index];
console.log('Trying to download whitelist');
console.log(cms._name + ' ' + cms._version);
downloadWhitelist(cms._name, cms._version);
}
}
//datatable filtering by timeslot and flags
$.fn.dataTable.ext.search.push(
function( settings, data, dataIndex ) {
var minDateStr = $('#dateMin').val();
var maxDateStr = $('#dateMax').val();
var flags = [];
$('.popup_name_flag').find('.list__line_checked_yes').each(function(){flags.push(this.getAttribute('val'))});
var minDate = new Date(minDateStr);
var maxDate = new Date(maxDateStr);
var date = new Date(data[4]); // use data for the mtime column
var flag = data[0];
if (flags.indexOf(flag) == -1) {
return false;
}
if ( ( minDateStr == '' && '' == maxDateStr ) ||
( minDateStr == '' && date <= maxDate ) ||
( minDate <= date && '' == maxDateStr ) ||
( minDate <= date && date <= maxDate ) )
{
return true;
}
return false;
}
);
function escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
function base64_decode(data) {
if (!data)
return "";
// discuss at: http://phpjs.org/functions/base64_decode/
// original by: Tyler Akins (http://rumkin.com)
// improved by: Thunder.m
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// input by: Aman Gupta
// input by: Brett Zamir (http://brett-zamir.me)
// bugfixed by: Onno Marsman
// bugfixed by: Pellentesque Malesuada
// bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
// returns 1: 'Kevin van Zonneveld'
// example 2: base64_decode('YQ===');
// returns 2: 'a'
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
ac = 0,
dec = '',
tmp_arr = [];
if (!data) {
return data;
}
data += '';
do { // unpack four hexets into three octets using index points in b64
h1 = b64.indexOf(data.charAt(i++));
h2 = b64.indexOf(data.charAt(i++));
h3 = b64.indexOf(data.charAt(i++));
h4 = b64.indexOf(data.charAt(i++));
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
o1 = bits >> 16 & 0xff;
o2 = bits >> 8 & 0xff;
o3 = bits & 0xff;
if (h3 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1);
} else if (h4 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1, o2);
} else {
tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
}
} while (i < data.length);
dec = tmp_arr.join('');
return dec.replace(/\0+$/, '');
}
function base64_encode( data ) { // Encodes data with MIME base64
//
// + original by: Tyler Akins (http://rumkin.com)
// + improved by: Bayron Guevara
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
do { // pack three octets into four hexets
o1 = data.charCodeAt(i++);
o2 = data.charCodeAt(i++);
o3 = data.charCodeAt(i++);
bits = o1<<16 | o2<<8 | o3;
h1 = bits>>18 & 0x3f;
h2 = bits>>12 & 0x3f;
h3 = bits>>6 & 0x3f;
h4 = bits & 0x3f;
// use hexets to index into b64, and append result to encoded string
enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
} while (i < data.length);
switch( data.length % 3 ){
case 1:
enc = enc.slice(0, -2) + '==';
break;
case 2:
enc = enc.slice(0, -1) + '=';
break;
}
return enc;
}
function buildTable(data) {
window.filesDataTable = $('#filesTable').dataTable({
"order": [[ 0, "desc" ]],
"aLengthMenu": [[100, 10, 500, -1], [100, 10, 500, "All"]],
"fnInitComplete": function(oSettings, json) {
showProgress(false);
turnOnTableScreen();
},
"iDisplayLength": 50,
//Localization
"oLanguage": {
"sLengthMenu": "Отображать по _MENU_ записей",
"sZeroRecords": "Ничего не найдено",
"sInfo": "Отображается c _START_ по _END_ из _TOTAL_ файлов",
"sInfoEmpty": "Нет файлов",
"sInfoFiltered": "(всего записей _MAX_)",
"sSearch": "Поиск:",
"sUrl": "",
"oPaginate": {
"sFirst": " ",
"sPrevious": " ",
"sNext": " ",
"sLast": " "
},
"oAria": {
"sSortAscending": ": активировать для сортировки столбца по возрастанию",
"sSortDescending": ": активировать для сортировки столбцов по убыванию"
}
},
//Data source
"aaData": data,
//Data preprocessing for rendering
"aoColumnDefs": [
//Detection flag field preprocessing
{
"aTargets": [0],
"bAutoWidth": false,
"sWidth" : "60px",
"sType": "html",
"sClass": "table__item",
//FIXME - profomance issue with tag stripping
//http://datatables.net/forums/discussion/3896/how-to-apply-sorting-on-hidden-column
"mRender": function (flag, type, full) {
if (flag == 'c') {
return '<span class="table__flag table__flag_color_red"><span style="display:none">3<span></span>';
} else if (flag == 'w') {
return '<span class="table__flag table__flag_color_yellow"><span style="display:none">2</span></span>';
}
return '<span class="table__flag table__flag_color_green"><span style="display:none">1</span></span>';
}
},
//File size field preprocessing
{
"aTargets": [1],
"bAutoWidth": false,
"sWidth" : "500px",
},
//File size field preprocessing
{
"aTargets": [2],
"bAutoWidth": false,
"sWidth" : "100px",
"sClass": "table__item",
"mRender": function (size, type, full) {
if (size > -1) {
return size;
} else {
return '';
}
}
},
//Ctime and mtime fields preprocessing
{
"aTargets": [3, 4],
"bAutoWidth": false,
"sWidth" : "250px",
"sClass": "table__item",
//"sType": "date",
"mRender": function (timestamp, type, full) {
return $.format.date(new Date(timestamp * 1000), "yyyy-MM-dd HH:mm:ss");
}
},
{
"aTargets": [1],
"sWidth" : "100px",
"sClass": "table__item",
},
{
"aTargets": [5, 6, 7],
"sClass": "table__item",
"visible": false
},
{
"aTargets": [8],
"sWidth" : "100px",
"bAutoWidth": false,
"sClass": "table__item",
"mRender": function (detectionInfo, type, full) {
var buttons = "<div class=\"button-group i-bem button-group_js_inited\" hash='" + base64_encode(detectionInfo.path) + "'><div class=\"popup popup_visibility_hidden i-bem popup_js_inited\" data-bem=\"{"popup":{"0":"t","1":"r","2":"u","3":"e"}}\"><div class=\"popup__close\"></div><div class=\"popup__content\"><table class=\"table\"><tbody><tr class=\"table__line\"><td class=\"table__item table__item_bold_yes\"> Hash </td><td class=\"table__item\">" + base64_encode(detectionInfo.path) + "</td></tr></tbody><tr class=\"table__line\"><td class=\"table__item table__item_bold_yes\"> Snippet </td><td class=\"table__item\">" + normalizeSnippet(base64_decode(detectionInfo.snippet)) + "</td></tr></table></div></div><button class=\"button_more_yes button i-bem\" data-bem=\"{"button":{}}\" role=\"button\" type=\"button\"><div class=\"button__arrow\"></div></button><button id=\"q_" + base64_encode(detectionInfo.path) + "\" class=\"button button_size_s i-bem\" data-bem=\"{"button":{}}\" role=\"button\" onclick=\"return add_quarantine('" + base64_encode(detectionInfo.path) + "', '" + detectionInfo.path + "')\"><span class=\"button__text quarantine\">" + localization.locale_dicts[localization.chosen_language]["TableScreen.Quarantine" ] + "</span></button><button id=\"d_" + base64_encode(detectionInfo.path) + "\" class=\"button button_size_s i-bem\" data-bem=\"{"button":{}}\" role=\"button\" onclick=\"return add_delete('" + base64_encode(detectionInfo.path) + "', '" + detectionInfo.path + "')\"><span class=\"button__text delete\">" + localization.locale_dicts[localization.chosen_language]["TableScreen.Delete"] + "</span></button></div>";
return buttons;
}
},
//md5 hash as a hidden column
{
"aTargets": [9],
"sClass": "table__item",
"visible": false
}
]
});
}
function filterColumns() {
$('.popup_name_columns').find('.list__line').each(function(){
var column = filesDataTable.DataTable().column( this.getAttribute('val') );
column.visible( $(this).hasClass('list__line_checked_yes') );
console.log(this.getAttribute('val'));
});
}
function applyFilter(filter_name, filter) {
filters[filter_name] = filter;
filter_stat[filter_name] = {'total': Object.keys(filters[filter_name]).length, 'filtered': 0}
//reset counter for each filter because stats is calculated
//for all filters again every time new filter is added
$.each(filter_stat, function(name, stat) {
filter_stat[name]['filtered'] = 0;
});
remove_control = '<a onclick="console.log($(this).parent().parent());" href="#">X</a>'
row = '<tr><td>' + filter_name + '</td><td>' + filter_stat[filter_name]['total'] + '</td>';
row += '<td id="fb_' + filter_name +'">' + filter_stat[filter_name]['filtered'] + '</td><td><input type="button" value="X" class="filter_list_button_remove"/></td></tr>';
$('#filter_file_list tr:last').after(row);
$('.filter_list').css('visibility', 'visible');
//redraw the table with newly added filter
$("#filesTable").dataTable().fnDraw();
//TODO: jquery selector doesn't work here
$(document.getElementById('fb_' + filter_name)).text(filter_stat[filter_name]['filtered']);
}
$('#filter_file_list').on('click', 'input[type="button"]', function(e){
row = $(this).closest('tr');
row.remove();
filename = row.children().first().text();
//remove filename from filter_list
delete filters[filename];
delete filter_stat[filename];
if (Object.keys(filters).length <= 0) {
$('.filter_list').css('visibility', 'hidden');
}
//redraw table
$("#filesTable").dataTable().fnDraw();
});
//whitelist filtering
var filter_stat = {}
$.fn.dataTableExt.afnFiltering.push(
function( oSettings, aData, iDataIndex )
{
var row = oSettings.aoData[iDataIndex].nTr;
filepath = $(row).children().eq(1).text();
hash = $(row).children().last().children().first().attr('hash');
var is_whitelisted = false;
$.each(filters, function(filter_name, filter) {
if (filter.hasOwnProperty(hash)) {
filter_stat[filter_name]['filtered'] += 1;
is_whitelisted = true;
}
});
return !is_whitelisted;
}
);