Skip to content

Commit

Permalink
Finish 1.5.0-beta
Browse files Browse the repository at this point in the history
  • Loading branch information
sarus committed Aug 22, 2017
2 parents 3bee78b + c6c60ec commit 47f9fca
Show file tree
Hide file tree
Showing 5 changed files with 795 additions and 45 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ If checked, the VirusTotal integration will send IPv4 addresses to VirusTotal fo

If checked, the VirusTotal integration will send MD5, SHA1, and SHA256 hashes to VirusTotal for lookup.

### Show Files (Hashes) with No Detections

Default: false

If checked, the VirusTotal integration will show files in the notification overlay that have no detections.

### API Key Limit Reach Warning

If checked, the VirusTotal integration will display warnings in the notification window when you have hit the VirusTotal lookup limit for the api key you are currently using.
If checked, the VirusTotal integration will display warnings in the notification overlay when you have hit the VirusTotal lookup limit for the api key you are currently using.

## Installation Instructions

Expand Down
9 changes: 9 additions & 0 deletions config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,15 @@ module.exports = {
"userCanEdit": true,
"adminOnly": false
},
{
"key": "showHashesWithNoDetections",
"name": "Show Files (Hashes) with No Detections",
"description": "If checked, the integration will show results for files that have no positive detections.",
"default": false,
"type": "boolean",
"userCanEdit": true,
"adminOnly": false
},
{
"key": "warnOnLookupLimit",
"name": "API Key Limit Reached Warning",
Expand Down
120 changes: 82 additions & 38 deletions integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function doLookup(entities, options, cb) {
const MAX_HASHES_PER_GROUP = options.isPrivateApi === true ? 25 : 4;

entities.forEach(function (entity) {
if(pendingLookupCache.isRunning(entity.value)){
if (pendingLookupCache.isRunning(entity.value)) {
pendingLookupCache.addPendingLookup(entity.value, cb);
return;
}
Expand All @@ -75,13 +75,15 @@ function doLookup(entities, options, cb) {
hashGroup = [];
}

hashGroup.push(entity.value);
entityLookup[entity.value.toLowerCase()] = entity;
if(!entityLookup[entity.value.toLowerCase()]){
// entity isn't already added
hashGroup.push(entity.value);
entityLookup[entity.value.toLowerCase()] = entity;
pendingLookupCache.addRunningLookup(entity.value);

pendingLookupCache.addRunningLookup(entity.value);

if (doLookupLogging === true) {
lookupHashSet.add(entity.value);
if (doLookupLogging === true) {
lookupHashSet.add(entity.value);
}
}
} else if (entity.isIPv4 && !entity.isPrivateIP && !IGNORED_IPS.has(entity.value) && options.lookupIps) {
if (doLookupLogging === true) {
Expand All @@ -103,7 +105,7 @@ function doLookup(entities, options, cb) {
ipLookups: function (callback) {
if (ipv4Entities.length > 0) {
async.concat(ipv4Entities, function (ipEntity, concatDone) {
Logger.debug({ip:ipEntity.value}, 'Looking up IP');
Logger.debug({ip: ipEntity.value}, 'Looking up IP');
_lookupIp(ipEntity, options, concatDone);
}, function (err, results) {
if (err) {
Expand All @@ -122,13 +124,13 @@ function doLookup(entities, options, cb) {
async.map(hashGroups, function (hashGroup, mapDone) {
_lookupHash(hashGroup, entityLookup, options, mapDone);
}, function (err, results) {
Logger.trace({hashLookupResults: results}, 'HashLookup Results');

if (err) {
callback(err);
return;
}

Logger.trace({hashLookupResults: results}, 'HashLookup Results');

//results is an array of hashGroup results (i.e., an array of arrays)
let unrolledResults = [];
results.forEach(function (hashGroup) {
Expand Down Expand Up @@ -172,7 +174,6 @@ function doLookup(entities, options, cb) {
}



function _handleRequestError(err, response, body, options, cb) {
if (err) {
cb(_createJsonErrorPayload("Unable to connect to VirusTotal server", null, '500', '2A', 'VirusTotal HTTP Request Failed', {
Expand Down Expand Up @@ -244,48 +245,93 @@ function _lookupHash(hashesArray, entityLookup, options, done) {
}

let hashLookupResults = [];
let tmpResult;

if (_.isArray(body)) {
_.each(body, function (item) {
hashLookupResults = _processHashLookupItem(item, entityLookup, hashLookupResults);
body.forEach(item => {
tmpResult = _processHashLookupItem(item, entityLookup, options.showHashesWithNoDetections);
if (tmpResult !== null) {
hashLookupResults.push(tmpResult);
}
});
//send the results to the user
} else {
hashLookupResults = _processHashLookupItem(body, entityLookup, hashLookupResults);
tmpResult = _processHashLookupItem(body, entityLookup, options.showHashesWithNoDetections);
if (tmpResult !== null) {
hashLookupResults.push(tmpResult);
}
}

done(null, hashLookupResults);
});
});
}

function _processHashLookupItem(virusTotalResultItem, entityLookupHash, hashLookupResults) {
function _processHashLookupItem(virusTotalResultItem, entityLookupHash, showHashesWithNoDetections) {
let entity = entityLookupHash[virusTotalResultItem.resource.toLowerCase()];

if (virusTotalResultItem.response_code === 1 ||
(virusTotalResultItem.positives === 0 && virusTotalResultItem.total === 0)) {
Logger.debug({
entityValue: entity.value,
positives: virusTotalResultItem.positives,
total: virusTotalResultItem.total,
responseCode: virusTotalResultItem.response_code
}, 'Result Item');

if (_isHashLookupResultHit(virusTotalResultItem, showHashesWithNoDetections)) {
virusTotalResultItem.type = 'file';
Logger.debug({hash: entity.value}, 'Had Result');
Logger.debug({hash: entity.value}, 'Lookup Had Result (Caching Hit)');

hashLookupResults.push({
return {
entity: entity,
data: {
summary: [util.format("%d <i class='fa fa-bug integration-text-bold-color'></i> / %d",
virusTotalResultItem.positives, virusTotalResultItem.total)],
details: virusTotalResultItem
}
});
} else if (virusTotalResultItem.response_code === 0 ||
(virusTotalResultItem.positives === 0 && virusTotalResultItem.total === 0)) {
Logger.debug({hash: entity.value}, 'No Result');
hashLookupResults.push({
};
} else if (_isHashLookupMiss(virusTotalResultItem)) {
Logger.debug({hash: entity.value}, 'No Result (Caching Miss)');
return {
entity: entity,
data: null
})
};
}

return hashLookupResults;
Logger.debug("Ignoring result due to no positive detections");
return null;
}

function _isHashLookupMiss(virusTotalResultItem) {
if (virusTotalResultItem.response_code === 0 ||
(virusTotalResultItem.positives === 0 && virusTotalResultItem.total === 0)) {
return true;
}

return false;
}

/**
* For there to be a hit the response_code must be 1. In addition, if the total number of positive
* detections is 0 then no hit will be returned unless `showHashWithNoDetections` is set to true.
*
* @param virusTotalResultItem
* @param showHashesWithNoDetections
* @returns {boolean}
* @private
*/
function _isHashLookupResultHit(virusTotalResultItem, showHashesWithNoDetections) {
if (virusTotalResultItem.response_code === 1) {

if (virusTotalResultItem.positives === 0 && showHashesWithNoDetections === false) {
return false;
}

return true;
}

return false;
}


function _lookupIp(ipEntity, options, done) {
//do the lookup
if (doLookupLogging === true) {
Expand Down Expand Up @@ -355,14 +401,14 @@ function _processIpLookupItem(virusTotalResultItem, ipEntity, ipLookupResults) {
// Compute the details
let details = _computeIpDetails(virusTotalResultItem);

if(details.numResolutions === 0 && details.overallPositives === 0 && details.overallTotal === 0){
if (details.numResolutions === 0 && details.overallPositives === 0 && details.overallTotal === 0) {
Logger.debug({ip: ipEntity.value}, 'No Positive Detections or Resolutions');
// This was an empty result so we just push a null data value
ipLookupResults.push({
entity: ipEntity,
data: null
})
}else{
} else {
Logger.debug({ip: ipEntity.value}, 'Had Result');
ipLookupResults.push({
entity: ipEntity,
Expand Down Expand Up @@ -500,33 +546,31 @@ function startup(logger) {
}

pendingLookupCache = new PendingLookupCache(logger);
if(config && config.settings && config.settings.trackPendingLookups){
if (config && config.settings && config.settings.trackPendingLookups) {
pendingLookupCache.setEnabled(true);
}

if(typeof config.request.cert === 'string' && config.request.cert.length > 0){
if (typeof config.request.cert === 'string' && config.request.cert.length > 0) {
requestOptionsIp.cert = fs.readFileSync(config.request.cert);
requestOptionsHash.cert = fs.readFileSync(config.request.cert);
}

if(typeof config.request.key === 'string' && config.request.key.length > 0){
if (typeof config.request.key === 'string' && config.request.key.length > 0) {
requestOptionsIp.key = fs.readFileSync(config.request.key);
requestOptionsHash.key = fs.readFileSync(config.request.key);
}

if(typeof config.request.passphrase === 'string' && config.request.passphrase.length > 0){
if (typeof config.request.passphrase === 'string' && config.request.passphrase.length > 0) {
requestOptionsIp.passphrase = config.request.passphrase;
requestOptionsHash.passphrase = config.request.passphrase;
}

if(typeof config.request.ca === 'string' && config.request.ca.length > 0){
if (typeof config.request.ca === 'string' && config.request.ca.length > 0) {
requestOptionsIp.ca = fs.readFileSync(config.request.ca);
requestOptionsHash.ca = fs.readFileSync(config.request.ca);
}else if(Array.isArray(config.request.ca)){
requestOptionsIp
}
}

if(typeof config.request.proxy === 'string' && config.request.proxy.length > 0){
if (typeof config.request.proxy === 'string' && config.request.proxy.length > 0) {
requestOptionsIp.proxy = config.request.proxy;
requestOptionsHash.proxy = config.request.proxy;
}
Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"main": "./integration.js",
"name": "VirusTotal",
"version": "1.4.0-beta",
"version": "1.5.0-beta",
"private": true,
"options": [
{
Expand All @@ -14,13 +14,14 @@
}
],
"dependencies": {
"request": "^2.75",
"lodash": "^4.16",
"async": "2.1.4"
"request": "^2.81",
"lodash": "^4.17",
"async": "^2.5"
},
"devDependencies": {
"chai": "~3.5",
"mocha": "~3.2"
"chai": "~4.1",
"mocha": "~3.4",
"nock": "~9.0"
},
"scripts": {
"test": "./node_modules/.bin/mocha --recursive"
Expand Down
Loading

0 comments on commit 47f9fca

Please sign in to comment.