@passmarked/malware
Version:
Rules that check if the page or linked pages on the same domain (or external) contain any unwanted software,malware or reported phishing attacks
248 lines (170 loc) • 5.74 kB
JavaScript
/**
* Required modules
**/
const async = require('async');
const crypto = require('crypto');
const url = require('url');
const request = require('request');
const querystring = require('querystring');
const S = require('string');
const _ = require('underscore');
const Constants = require('../constants');
/**
* Object to expose
**/
var SafeBrowsing = {};
/**
* Generates a hash for the domain that is used
* by the API.
**/
SafeBrowsing.getHash = function(payload, link, fn) {
// remove the query and hash params
var uri = url.parse( (link || '').toLowerCase() );
// remove the hash
uri.hash = '';
uri.search = '';
// create the hash object
var sha = crypto.createHash('sha1');
sha.update( url.format(uri) );
var hash = sha.digest('hex');
// use it
fn(null, hash);
};
/**
* Handles the response from the service
**/
SafeBrowsing.callback = function(payload, link, responseText, fn) {
// the value
var detections = [];
// split the results
var results = (responseText || '').split(',');
// go through the results one by one
async.each(results, function(result, cb) {
// local reference
var result = S(result || '').trim().s.toLowerCase();
// sanity check
if(S(result).isEmpty() === true) return cb(null);
// skip if all good
if(result === 'ok') return cb(null);
// the type we will go searching for
var type = null;
// get the keys of the known types
var knownKeys = _.keys(Constants.DETECTIONS);
// get the known types
for(var i = 0; i < knownKeys.length; i++) {
// does this type match ?
if( Constants.DETECTIONS[knownKeys[i]] === result )
type = Constants.DETECTIONS[knownKeys[i]];
}
// must be a known type
if(!type) return cb(null);
// add it
detections.push({
source: Constants.SAFEBROWSING_SOURCE, // API name
provider: Constants.SAFEBROWSING_COMPANY, // Company Name
preview: 'https://www.google.com/transparencyreport/safebrowsing/diagnostic/#url=' + S(link || '').trim().s,
website: Constants.SAFEBROWSING_WEBSITE,
result: results,
type: type,
url: link
});
// done
cb(null);
}, function(err) {
// handle the output
if(err) {
// output as error
payload.error('Something went wrong while parsing the results from SAFE BROWSING: ' + results, err);
}
// finish with the error if given
fn(err, detections);
});
};
/**
* Does the actual check
**/
SafeBrowsing.check = function(payload, link, fn) {
// get the payload data (mostly for testing)
var data = payload.getData();
// get the key
var SAFEBROWSING_API_KEY = process.env.SAFEBROWSING_API_KEY || data.SAFEBROWSING_API_KEY || null;
var SAFEBROWSING_CLIENT = process.env.SAFEBROWSING_CLIENT || data.SAFEBROWSING_CLIENT || null;
// parse the url
var uri = url.parse(link);
// get the hash
SafeBrowsing.getHash(payload, link, function(err, hash) {
// handle a error if any
if(err) {
// output error
payload.error('Something went wrong while generating the hash for SafeBrowsing from link ' + link, err);
// finish
return fn(err, []);
}
// the key to use for caching
var cachingKey = [
'passmarked',
'safebrowsing',
hash
].join(':');
// check the cache
payload.get(cachingKey, function(err, cachedResults) {
// handle any errors
if(err) {
// output to stderr
payload.error('Problem checking cache for Safe Browsing results', err);
// even if the cache is not working still continue
return fn(err, []);
}
// was it cached ?
if(cachedResults) {
// send it to be handled as a callback
return SafeBrowsing.callback(payload, link, cachedResults, fn);
}
// check the environment variables were given
if(!SAFEBROWSING_API_KEY ||
!SAFEBROWSING_CLIENT) {
// warn
payload.warning('SafeBrowsing requires the env variables SAFEBROWSING_API_KEY and SAFEBROWSING_CLIENT to work, returning blank results for now');
// just return the results
return fn(null, []);
}
// generate the options for our request
var options = {
url: 'https://sb-ssl.google.com/safebrowsing/api/lookup?' + querystring.stringify({
client: SAFEBROWSING_CLIENT || '',
key: SAFEBROWSING_API_KEY || '',
appver: '1.5.2',
pver: '3.1',
url: link
}),
timeout: 1000 * 10
};
// do the request
request(options, function(err, response, body) {
// handle the output
if(err) {
// output as error
payload.error('Something went wrong while doing the request to the SAFE BROWSING API with the url ' + options.uri, err);
// return the actual error
return fn(err);
}
// response must be defined and a 200
if(!response || response.statusCode !== 200) return fn(null);
// set in cache
payload.set(cachingKey, body || '', function(err) {
// check for a error
if(err) {
// output but don't stop exec
payload.error('Something went wrong while setting the Safe Browsing results in cache', err);
}
// send it to be handled as a callback
SafeBrowsing.callback(payload, link, body || '', fn);
});
});
});
});
};
/**
* Expose the given object
**/
module.exports = exports = SafeBrowsing;