browser-node-virustotal
Version:
An implementation of the Virustotal API for client js
783 lines (781 loc) • 26.1 kB
JavaScript
const request = require("browser-request-fix");
const stream = require("stream");
const commentSender = require("./commentSender.js");
var features = {};
const leftPad = function(raw, length, padPhrase) {
var workingString = "" + raw;
while (workingString.length < length) {
workingString = padPhrase + workingString;
}
return workingString;
};
const dateToString = function(input){
return ((((input.getFullYear() + "-") + (leftPad(input.getMonth() + 1, 2, "0") + "-" )) + ((leftPad(input.getDate(), 2, "0") + "T" ) + (leftPad(input.getHours(), 2, "0") + ":" ))) + ((leftPad(input.getMinutes(), 2, "0") + ":") + leftPad(input.getSeconds(), 2, "0")));
};
var rescan = function(resource, key){
var dateString = null;
var period = null;
var repeatCount = null;
var changesOnly = 0;
var notifyURL = null;
this.setDate = function(year, month, day, hour, minute, second){
year = leftPad("" + year, 4, "20");
month = leftPad("" + month, 2, "0");
day = leftPad("" + day, 2, "0");
hour = leftPad("" + hour, 2, "0");
minute = leftPad("" + minute, 2, "0");
second = leftPad("" + second, 2, "0");
dateString = (year + month) + (day + hour) + (minute + second);
return this;
};
this.setPeriod = function(input){
period = input;
return this;
};
this.setRepeatCount = function(input) {
repeatCount = input;
return this;
};
this.setNotifyURL = function(replacement){
notifyURL = replacement;
return this;
};
this.setNotifyChangesOnly = function(input) {
switch(input) {
case null:
changesOnly = 0;
return this;
case 1:
case true:
changesOnly = 1;
return this;
case 0:
case false:
default:
changesOnly = 0;
return this;
}
return this;
};
this.sendRequest = function(responseProc, errProc){
var formattedRequest = ("https://www.virustotal.com/vtapi/v2/file/rescan?apikey=" + key) + ("&resource=" + resource);
if (dateString != null) {
formattedRequest = formattedRequest + ("&date=" + dateString);
}
if (period != null) {
formattedRequest = formattedRequest + ("&period=" + period);
}
if (repeatCount != null) {
formattedRequest = formattedRequest + ("&repeat=" + repeatCount);
}
if (notifyURL != null) {
formattedRequest = formattedRequest + (("¬ify_url=" + notifyURL) + ("¬ify_changes_only" + changesOnly));
}
request({url: formattedRequest, method: "POST", gzip: true, headers: { "User-Agent": "gzip"}}, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
switch (data.response_code) {
case 1:
responseProc(data);
return;
case 0:
case -1:
case -2:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
return this;
};
this.cancel = function(responseProc, errProc) {
var cancelUrl = ("https://www.virustotal.com/vtapi/v2/file/rescan/delete?apikey=" + key) + ("&resource=" + resource);
request({url: cancelUrl, method: "POST", gzip: true, headers: { "User-Agent": "gzip"}}, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
data = JSON.parse(body);
switch (data.response_code) {
case 1:
responseProc(data);
return;
case 0:
case -1:
case -2:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
return this;
};
return;
};
var privateAPI = function(){
var key = "";
this.setKey = function(replacement){
key = replacement;
return this;
};
this.getKey = function(){
return key;
}
var getComments = function(resource, responseProc, errProc) {
var queryURL = "https://www.virustotal.com/vtapi/v2/comments/get?resource=" + resource + "&apikey=" + key;
request(queryURL, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
switch (data.response_code) {
case 1:
case 0:
responseProc(data);
return;
case -1:
case -2:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
};
var publishUrlComment = function(resource, comment, resultProc, errProc){
if (errProc==null) {
errProc = function(e) {
publishUrlComment(resource, comment, resultProc, null);
return;
}
}
var workingSender = new commentSender(resource, comment, key, resultProc, errProc);
workingSender.attempt();
return;
};
var getReport = function(queryURL, responseProc, errProc) {
request(queryURL, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
switch (data.response_code) {
case 1:
case 0:
responseProc(data);
return;
case -1:
case -2:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
return;
};
var upperLimit = 32*1024*1024;
var sendFileToURL = function(filename, filetype, content, URL, callback){
var sendOptions = {
url: URL,
formData: {file: { value: filecontent, options: { filename: filename, filetype: filetype}}}
};
request.post(sendOptions, callback);
};
var sendFilePreLogic = function(filename, filetype, content, resultProc, errProc){
var callbackProc = function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
switch (data.response_code) {
case 1:
resultProc(data);
return;
case 0:
case -1:
case -2:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
};
if (content.length < upperLimit ) {
sendFileToURL(filename, filetype, content, "https://www.virustotal.com/vtapi/v2/file/scan?apikey=" + key, callbackProc);
return;
}
request.get("https://www.virustotal.com/vtapi/v2/file/scan/upload_url?apikey=" + key, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
sendFileToURL(filename, filetype, content, data.upload_url, callbackProc);
return;
} catch (e) {
errProc(e);
return;
}
});
return;
};
var submitUrlForScanning = function(URL, resultProc, errProc){
var fullURL = "https://www.virustotal.com/vtapi/v2/url/scan?url=" + encodeURIComponent(URL) + "&apikey=" + key;
request({url: URL, method:"POST"}, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try{
var data = JSON.parse(body);
switch(data.response_code) {
case 1:
resultProc(data);
return;
case 0:
case -1:
case -2:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
};
var retrieveUrlAnalysis = function(URL, responseProc, errProc, rescan, extendedData, continueProc) {
var query = "https://www.virustotal.com/vtapi/v2/url/report?apikey=" + key + "&url=" + encodeURIComponent(URL);
if (rescan==true) {
query = query + "&rescan=1";
}
if (extendedData==true) {
query = query + "&allinfo=1";
}
request.get(query, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
switch (data.response_code) {
case -2:
if (continueProc==null) {
var next = function(){
retrieveUrlAnalysis(URL, responseProc, errProc, false, extendedData, null);
};
setTimeout(next, 300000);
return;
}
continueProc(data);
return;
case 1:
case 0:
responseProc(data);
return;
case -1:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
return;
};
var getFileReport = function(scanID, responseProc, errProc, extendedData, continueProc){
var fileResourceURL = "https://www.virustotal.com/vtapi/v2/file/report?apikey=" + key + "&resource=" + scanID;
if (extendedData==true) {
fileResourceURL = fileResourceURL + "&allinfo=1";
}
request(fileResourceURL, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
switch (data.response_code) {
case -2:
if (continueProc==null) {
var next = function(){
getFileReport(scanID, responseProc, errProc, extendedData, null);
};
setTimeout(next, 300000);
return;
}
continueProc(data);
return;
case 1:
case 0:
responseProc(data);
return;
case -1:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
};
var getFile = function(hashCode, responseProc, errProc){
var requestURL = "https://www.virustotal.com/vtapi/v2/file/download?apikey=" + key + "&hash=" + hashCode;
var getFileProc = function(){
request(requestURL, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode == 404) {
errProc(response);
return;
}
if (response.statusCode > 399) {
getFileProc();
return;
}
responseProc(body);
return;
});
};
return;
};
var makeRescan = function(resource) {
return new rescan(resource, key);
};
var getFileBehavior = function(resource, responseProc, errProc) {
request("https://www.virustotal.com/vtapi/v2/file/behaviour?apikey=" + key + "&hash=" + resource, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
if (data.response_code) {
errProc(data);
return;
}
responseProc(data);
return;
} catch (e) {
errProc(e);
return;
}
});
return;
};
var getFileNetworkActivity = function(resource, responseProc, errProc) {
request("https://www.virustotal.com/vtapi/v2/file/network-traffic?apikey=" + key + "&hash=" + resource, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
if (data.response_code) {
errProc(data);
return;
}
responseProc(data);
return;
} catch (e) {
errProc(e);
return;
}
});
return;
};
var getClusters = function(year, month, date, resultProc, errProc){
var queryString = "https://www.virustotal.com/vtapi/v2/file/clusters?apikey=" + key + "&date=" + leftPad(year+"", 4, "20") + "-" + leftPad(month+"",2,"0") + "-" + leftPad(date+"",2,"0");
request(queryString, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
switch(data.response_code) {
case 1:
case 0:
resultProc(data);
return;
case -1:
case -2:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
return;
};
var getNextFalsePositive = function(resultProc, errProc){
request({
url: "https://www.virustotal.com/vtapi/v2/file/false-positives?limit=1&apikey=" + key,
gzip: true,
headers: {
"User-Agent": "gzip"
}
}, function(err, response, body){
if (err) {
errProc(err);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
if (data.length > 0) {
resultProc(data[0]);
return;
}
resultProc({});
return;
} catch (e) {
errProc(e);
return;
}
});
return;
};
var search2 = function(queryString, offset, responseProc, errProc) {
var queryURL = "https://www.virustotal.com/vtapi/v2/file/search?apikey=" + key + "&query=" + queryString;
if ((offset != null)&&(offset!="")) {
queryURL = queryURL + "&offset=" + queryObject.offset;
}
request(queryURL, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
switch (data.response_code) {
case 0:
case 1:
if (data.offset==null) {
data.offset = "";
}
if (data.hashes == null) {
data.hashes = [];
}
responseProc(data);
return;
case -1:
case -2:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
};
/*Note: search has been depreciated*/
var search = function(queryObject, offset, responseProc, errProc){
var queryURL = "https://www.virustotal.com/vtapi/v2/file/search?apikey=" + key + "&query=";
var queryComponents = [];
if (queryObject.type != null) {
queryComponents[queryComponents.length] = "type%3A" + queryObject.type;
}
if (queryObject.name != null) {
queryComponents[queryComponents.length] = "name%3A\"" + queryObject.name + "\"";
}
if (queryObject.lowerSize != null) {
queryComponents[queryComponents.length] = "size%3A" + queryObject.lowerSize + "%2B";
}
if (queryObject.upperSize != null) {
queryComponents[queryComponents.length] = "size%3A" + queryObject.upperSize + "-";
}
if (queryObject.tag != null) {
queryComponents[queryComponents.length] = "tag%3A" + queryObject.tag;
}
if (queryObject.firstSubmittedBefore) {
queryComponents[queryComponents.length] = "fs%3A" + dateToString(queryObject.firstSubmittedBefore) + "-";
}
if (queryObject.firstSubmittedAfter) {
queryComponents[queryComponents.length] = "fs%3A" + dateToString(queryObject.firstSubmittedAfter) + "%2B";
}
if (queryObject.lastSubmittedBefore) {
queryComponents[queryComponents.length] = "ls%3A" + dateToString(queryObject.lastSubmittedBefore) + "-";
}
if (queryObject.lastSubmittedAfter) {
queryComponents[queryComponents.length] = "ls%3A" + dateToString(queryObject.lastSubmittedAfter) + "%2B";
}
if (queryObject.AtLeastPositives != null) {
queryComponents[queryComponents.length] = "positives%3A" + queryObject.AtLeastPositives + "%2B";
}
if (queryObject.AtMostPositives != null) {
queryComponents[queryComponents.length] = "positives%3A" + queryObject.AtMostPositives + "-";
}
if (queryObject.AtLeastChildPositives != null) {
queryComponents[queryComponents.length] = "children_positives%3A" + queryObject.AtLeastChildPositives + "%2B";
}
if (queryObject.AtMostChildPositives != null) {
queryComponents[queryComponents.length] = "children_positives%3A" + queryObject.AtMostChildPositives + "-";
}
if (queryObject.AtLeastSubmissions != null) {
queryComponents[queryComponents.length] = "submissions%3A" + queryObject.AtLeastSubmissions + "%2B";
}
if (queryObject.AtMostSubmissions != null) {
queryComponents[queryComponents.length] = "submissions%3A" + queryObject.AtMostSubmissions + "-";
}
if (queryObject.AtLeastSources != null) {
queryComponents[queryComponents.length] = "sources%3A" + queryObject.AtLeastSources + "%2B";
}
if (queryObject.AtMostSources != null) {
queryComponents[queryComponents.length] = "sources%3A" + queryObject.AtMostSources + "-";
}
if (queryObject.RegionOfFirstSubmitter != null) {
queryComponents[queryComponents.length] = "submitter%3A" + queryObject.RegionOfFirstSubmitter;
}
if (queryObject.itw != null) {
queryComponents[queryComponents.length] = "itw%3A\"" + encodeURIComponent(queryObject.itw) + "\"";
}
if (queryObject.metadataString != null) {
queryComponents[queryComponents.length] = "metadata%3A\"" + encodeURIComponent(queryObject.metadataString) + "\"";
}
if (queryObject.metadataLiteral != null) {
queryComponents[queryComponents.length] = "metadata%3A" + queryObject.metadataLiteral;
}
if (queryObject.containsAndroguardResult != null) {
queryComponents[queryComponents.length] = "androguard%3A\"" + encodeURIComponent(queryObject.containsAndroguardResult) + "\"";
}
if (queryObject.containsLanguage != null) {
queryComponents[queryComponents.length] = "lang%3A\"" + encodeURIComponent(queryObject.containsAndroguardResult) + "\"";
}
if (queryObject.containsSignatureString != null) {
queryComponents[queryComponents.length] = "signature%3A\"" + encodeURIComponent(queryObject.containsSignatureString) + "\"";
}
if (queryObject.compilationDatetimeMin != null) {
queryComponents[queryComponents.length] = "signature%3A" + dateToString(queryObject.compilationDatetimeMin) + "-";
}
if (queryObject.compilationDatetimeMax != null) {
queryComponents[queryComponents.length] = "signature%3A" + dateToString(queryObject.compilationDatetimeMax) + "%2B";
}
if (queryObject.compilationSubmissionDifferenceMin != null) {
queryComponents[queryComponents.length] = "subspan%3A" + queryObject.compilationSubmissionDifferenceMin + "-";
}
if (queryObject.compilationSubmissionDifferenceMax != null) {
queryComponents[queryComponents.length] = "subspan%3A" + queryObject.compilationSubmissionDifferenceMax + "%2B";
}
if (queryObject.containsSectionLabel != null) {
queryComponents[queryComponents.length] = "section%3A\"" + encodeURIComponent(queryObject.containsSectionLabel) + "\"";
}
if (queryObject.containsMD5SectionLabel != null) {
queryComponents[queryComponents.length] = "section%3A" + queryObject.containsMD5SectionLabel;
}
if (queryObject.containsSegmentLabel != null) {
queryComponents[queryComponents.length] = "segment%3A\"" + encodeURIComponent(queryObject.containsSegmentLabel) + "\"";
}
if (queryObject.importsLibrary != null) {
queryComponents[queryComponents.length] = "imports%3A\"" + encodeURIComponent(queryObject.importsLibrary) + "\"";
}
if (queryObject.exportsFunction != null) {
queryComponents[queryComponents.length] = "exports%3A\"" + encodeURIComponent(queryObject.exportsFunction) + "\"";
}
if (queryObject.containsPhraseInBehaviorReport != null) {
queryComponents[queryComponents.length] = "behavior%3A\"" + encodeURIComponent(queryObject.containsPhraseInBehaviorReport) + "\"";
}
if (queryObject.containsResourceType != null) {
queryComponents[queryComponents.length] = "resource%3A\"" + encodeURIComponent(queryObject.containsResourceType) + "\"";
}
if (queryObject.containsHashedResource != null) {
queryComponents[queryComponents.length] = "resource%3A\"" + queryObject.containsHashedResource + "\"";
}
if (queryObject.generatesSnortAlertString != null) {
queryComponents[queryComponents.length] = "snort%3A\"" + encodeURIComponent(queryObject.generatesSnortAlertString) + "\"";
}
if (queryObject.generatesSnortAlertID != null) {
queryComponents[queryComponents.length] = "snort%3A" + queryObject.generatesSnortAlertID;
}
if (queryObject.generatesSuricataAlertString != null) {
queryComponents[queryComponents.length] = "suricata%3A\"" + encodeURIComponent(queryObject.generatesSuricataAlertString) + "\"";
}
if (queryObject.generatesSuricataAlertID != null) {
queryComponents[queryComponents.length] = "suricata%3A" + queryObject.generatesSuricataAlertID;
}
if (queryObject.hasTrafficWith != null) {
queryComponents[queryComponents.length] = "traffic%3A\"" + encodeURIComponent(queryObject.hasTrafficWith) + "\"";
}
if (queryObject.structurallySimilarTo != null) {
queryComponents[queryComponents.length] = "similar-to%3A" + queryObject.structurallySimilarTo;
}
if (queryObject.similarTo != null) {
if ((queryObject.similarTo.score != null) && (queryObject.similarTo.hash != null)) {
queryComponents[queryComponents.length] = "ssdeep%3A" + queryObject.similarTo.hash + "-" + queryObject.similarTo.score;
}
}
if (queryObject.importHash != null) {
queryComponents[queryComponents.length] = "imphash%3A" + queryObject.importHash;
}
if (queryObject.containsString) {
queryComponents[queryComponents.length] = "content%3A\"" + encodeURIComponent(queryObject.containsString) + "\"";
}
if (queryObject.containsHexSequence) {
queryComponents[queryComponents.length] = "content%3A" + queryObject.containsHexSequence;
}
queryURL = queryURL + queryComponents.join(" ");
if ((queryObject.offset != null)&&(queryObject.offset!="")) {
queryURL = queryURL + "&offset=" + queryObject.offset;
}
request(queryURL, function(error, response, body){
if (error) {
errProc(error);
return;
}
if (response.statusCode > 399) {
errProc(body);
return;
}
try {
var data = JSON.parse(body);
switch (data.response_code) {
case 0:
case 1:
if (data.offset==null) {
data.offset = "";
}
if (data.hashes == null) {
data.hashes = [];
}
responseProc(data);
return;
case -1:
case -2:
default:
errProc(data);
return;
}
} catch (e) {
errProc(e);
return;
}
});
};
this.search2 = search2;
this.search = search;
this.getNextFalsePositive = getNextFalsePositive;
this.getClusters = getClusters;
this.getFileNetworkActivity = getFileNetworkActivity;
this.getFileBehavior = getFileBehavior;
this.makeRescan = makeRescan;
this.getFile = getFile;
this.getFileReport = getFileReport;
this.retrieveUrlAnalysis = retrieveUrlAnalysis;
this.submitFileForAnalysis = sendFilePreLogic;
this.getDomainReport = function(domain, responseProc, errProc){
getReport("https://www.virustotal.com/vtapi/v2/domain/report?domain=" + domain + "&apikey=" + key, responseProc, errProc);
return;
};
this.getIP4Report = function(ip, responseProc, errProc){
getReport("https://www.virustotal.com/vtapi/v2/ip-address/report?ip=" + ip + "&apikey=" + key, responseProc, errProc);
return;
};
this.submitUrlForScanning = submitUrlForScanning;
this.publishFileComment = publishUrlComment;
this.publishUrlComment = publishUrlComment;
this.getFileComments = getComments;
this.getUrlComments = getComments;
return;
};
features.makePrivateAPI = function(){
return new privateAPI();
};
module.exports = exports = features;