UNPKG

@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
/** * 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;