Skip to content

Commit

Permalink
Update interface is backwards compatible.
Browse files Browse the repository at this point in the history
  • Loading branch information
this-sam committed Sep 10, 2021
1 parent e5341b1 commit 0afe8aa
Show file tree
Hide file tree
Showing 5 changed files with 905 additions and 17 deletions.
2 changes: 1 addition & 1 deletion bin/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/**
* Update our definition file.
*/
require('../lib/update').update(undefined, function updating(err, data) {
require('../lib/update').update(function updating(err, data) {
if (err) {
console.error('Update unsuccessfull due to reasons');
console.log(err.message);
Expand Down
25 changes: 18 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,13 +357,14 @@ Device.prototype.toJSON = function toJSON() {

/**
* Small nifty thick that allows us to download a fresh set regexs from a remote
* source. Package uses the compiled version by default, but allow for updating from
* the default source (no args) or a custom source, via the `remote` parameter.
* source. Package uses the compiled version by default, but allows for updating
* from the default source (no args) or a custom source, via the "remote"
* parameter.
*
* @param {String} remote optionally specify a custom URL for regex sourcing
* @param {String} [remote] optionally specify a custom URL for regex sourcing
* @api public
*/
module.exports = function updater(remote) {
module.exports = function updater(remote) {
try {
require('./lib/update').update(remote, function updating(err, results) {
if (err) {
Expand Down Expand Up @@ -415,10 +416,15 @@ function isSafe(userAgent) {
var consecutive = 0
, code = 0;

if (userAgent.length > 1000) return false;

for (var i = 0; i < userAgent.length; i++) {
code = userAgent.charCodeAt(i);
// numbers between 0 and 9, letters between a and z
if ((code >= 48 && code <= 57) || (code >= 97 && code <= 122)) {
if ((code >= 48 && code <= 57) || // numbers
(code >= 65 && code <= 90) || // letters A-Z
(code >= 97 && code <= 122) || // letters a-z
code <= 32 // spaces and control
) {
consecutive++;
} else {
consecutive = 0;
Expand All @@ -443,6 +449,10 @@ function isSafe(userAgent) {
* @api public
*/
exports.parse = function parse(userAgent, jsAgent) {
if (userAgent && userAgent.length > 1000) {
userAgent = userAgent.substring(0, 1000);
}

if (!userAgent || !isSafe(userAgent)) return new Agent();

var length = agentparserslength
Expand Down Expand Up @@ -506,7 +516,8 @@ exports.parse = function parse(userAgent, jsAgent) {
* @param {String} jsAgent Optional UA from js to detect chrome frame
* @api public
*/
var LRU = require('lru-cache')(5000);
var lruCache = require('lru-cache');
var LRU = new lruCache(5000);
exports.lookup = function lookup(userAgent, jsAgent) {
var key = (userAgent || '')+(jsAgent || '')
, cached = LRU.get(key);
Expand Down
66 changes: 59 additions & 7 deletions lib/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,44 @@ var request = require('request')
, yaml = require('yamlparser');

/**
* Update the regexp.js file
* Local modules.
*/
var old = require('./regexps');

function getKnown(old) {
var known = new Set();
for (var type in old) {
if (!old.hasOwnProperty(type)) continue;
var group = old[type];
for (var i = 0; i < group.length; i++) {
var regex = group[i][0].source;
known.add(regex);
}
}
return known;
}

var known = getKnown(old);

function isSafe(source) {
if (!/[+*{].*[+*{]/.test(source)) return true; // -35%
return false;
}

/**
* Update the regexps.js file
*
* @param {String} remote optional remote URL for regex source
* @param {String} [remote] optional remote URL for regex source
* @param {Function} callback Completion callback.
* @api public
*/
exports.update = function update(remote, callback) {
exports.update = function update() {
let remote, callback;

if (arguments.length === 2) [remote, callback] = arguments;
else if (arguments.length === 1) [callback] = arguments;
if (remote !== undefined) exports.remote = remote;

// Prepend local additions that are missing from the source
fs.readFile(exports.before, 'utf8', function reading(err, before) {
if (err) return callback(err);
Expand All @@ -47,10 +77,8 @@ exports.update = function update(remote, callback) {
//
tmp.file(function (err, tempFilePath) {
if (err) return;

fs.writeFile(tempFilePath, source, function idk(err) {
if (err) return

fs.rename(tempFilePath, exports.output, function(err) {

});
Expand All @@ -70,6 +98,7 @@ exports.update = function update(remote, callback) {
* @api public
*/
exports.parse = function parse(sources, callback) {
var unsafe = [];
var results = {};

var data = sources.reduce(function parser(memo, data) {
Expand Down Expand Up @@ -124,16 +153,29 @@ exports.parse = function parse(sources, callback) {
var resources = data[details.resource]
, name = details.resource.replace('_parsers', '')
, resource
, regex
, source
, parser;

for (var i = 0, l = resources.length; i < l; i++) {
resource = resources[i];
regex = resource.regex;

source = new RegExp(regex).source;
if (!known.has(source)) {
// A quick check, regexes not matching those are clearly safe
// This check excludes about 35% of all regexps we have
if (!isSafe(source)) {
unsafe.push(source);
}
known.add(source);
}

// We need to JSON stringify the data to properly add slashes escape other
// kinds of crap in the RegularExpression. If we don't do thing we get
// some illegal token warnings.
parser = 'parser = Object.create(null);\n';
parser += 'parser[0] = new RegExp('+ JSON.stringify(resource.regex) + ');\n';
parser += 'parser[0] = new RegExp('+ JSON.stringify(regex) + ');\n';

// Check if we have replacement for the parsed family name
if (resource[details.replacement]) {
Expand Down Expand Up @@ -172,6 +214,16 @@ exports.parse = function parse(sources, callback) {
}
});

if (unsafe.length > 0) {
console.log('There are new regexps! Here they are, one per line:');
for (var i = 0; i < unsafe.length; i++) {
console.log(' ' + unsafe[i]);
}
console.log('Those might be potentially unsafe and cause ReDoS.');
console.log('Make sure to take them through Weideman\'s tool and to inspect them!');
console.log('See https://github.com/NicolaasWeideman/RegexStaticAnalysis');
}

// Generate a correct format
exports.generate(results, callback);
};
Expand Down Expand Up @@ -222,7 +274,7 @@ exports.generate = function generate(results, callback) {
* @type {String}
* @api private
*/
exports.remote = 'https://raw.githubusercontent.com/ua-parser/uap-core/master/regexes.yaml';
exports.remote = process.env.USERAGENT_REMOTE ? process.env.USERAGENT_REMOTE : 'https://raw.githubusercontent.com/ua-parser/uap-core/master/regexes.yaml';

/**
* The locations of our local regexes yaml files.
Expand Down

0 comments on commit 0afe8aa

Please sign in to comment.