Last active
August 29, 2015 14:08
-
-
Save dweinstein/762072b69e5266110f9e to your computer and use it in GitHub Desktop.
VirusTotal cacheing API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var restify = require('restify'); | |
var jsonschema = require('jsonschema'); | |
var lodash = require('lodash'); | |
var util = require('util'); | |
var fmt = util.format; | |
var Promise = require('bluebird'); | |
var config = require('config').virustotal; | |
var logger = require('../logger'); | |
var VirusTotal = (function(config) { | |
var Reports = { | |
file: { | |
path: "/vtapi/v2/file/report", | |
scheme: { | |
id: "/file", | |
type: "object", | |
required: [ "resource" ], | |
properties: { | |
"resource": { "type": "string" } | |
} | |
} | |
}, | |
domain: { | |
path: "/vtapi/v2/domain/report", | |
scheme: { | |
id: "/domain", | |
type: "object", | |
required: [ "domain" ], | |
properties: { | |
"domain": { "type": "string" } | |
} | |
} | |
}, | |
url: { | |
path: "/vtapi/v2/url/report", | |
scheme: { | |
id: "/url", | |
type: "object", | |
required: [ "resource" ], | |
properties: { | |
"resource": { "type": "string", "format": "uri" } | |
} | |
} | |
}, | |
ip: { | |
path: "/vtapi/v2/ip-address/report", | |
scheme: { | |
id: "/ip", | |
type: "object", | |
required: [ "ip" ], | |
properties: { | |
"ip": { "type": "string" } | |
} | |
} | |
} | |
}; | |
var Validator = require('jsonschema').Validator; | |
var validator = new Validator(); | |
/** | |
* Memoized get client. Retrieves a (cached) JSON client object for the host/port | |
* @param {String} url - e.g., http://10.10.173.52:3000 | |
* @return {RestifyJsonClient} | |
*/ | |
var getClient = lodash.memoize(function (url) { | |
var client = restify.createJsonClient({ | |
url: url, | |
log: logger | |
}); | |
return Promise.promisifyAll(client); | |
}); | |
var restClient = getClient(config.url); | |
lodash.chain(Reports) | |
.pluck('scheme') | |
.each(function (val, key) { | |
validator.addSchema(val, val.id); | |
}); | |
function validate(type, opt) { | |
return new Promise(function (resolve, reject) { | |
if (!Reports[type]) { | |
return reject(new Error('unknown report type')); | |
} | |
var path = Reports[type].path; | |
var validation = validator.validate(opt, type); | |
if (validation.valid !== true) { | |
return reject(new Error(fmt('invalid data %s', validation.errors))); | |
} | |
return resolve(opt); | |
}); | |
} | |
function getPath(type) { | |
return Reports[type].path; | |
} | |
function getScheme(type) { | |
return Reports[type].scheme; | |
} | |
var getQuery = lodash.memoize(function (path, client) { | |
return client.getAsync(path) | |
.spread(function (req, res, obj) { | |
if (res.statusCode !== 200) { | |
throw new Error(fmt('error status: %s', res.statusCode)); | |
} | |
return obj; | |
}, function (err) { | |
util.log(err); | |
return {success: false}; | |
}); | |
}); | |
setInterval(function () { | |
util.log('clearing cache!'); | |
getQuery.cache = {}; | |
}, 120*60*1000); | |
function buildQuery(client, path, query) { | |
var qs = require('querystring'); | |
query = lodash.merge({ | |
apikey: config.apikey | |
}, query); | |
var fullPath = fmt("%s?%s", path, qs.stringify(query)); | |
return getQuery(fullPath, client); | |
} | |
function getReport(type, data) { | |
return validate(type, data) | |
.then(function (query) { | |
return buildQuery(restClient, getPath(type), data); | |
}); | |
} | |
return { | |
/** | |
* getReport | |
* @param {String} type - report type. | |
* @param {Object} data - report data. | |
* @return {Promise} | |
*/ | |
getReport: getReport | |
}; | |
})(config); | |
module.exports = VirusTotal; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment