Skip to content

Instantly share code, notes, and snippets.

@dweinstein
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dweinstein/762072b69e5266110f9e to your computer and use it in GitHub Desktop.
Save dweinstein/762072b69e5266110f9e to your computer and use it in GitHub Desktop.
VirusTotal cacheing API
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