diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b96524..527ff1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + +* Fix possible regular expression catastrophic backtracking [\#105](https://github.com/anandthakker/doiuse/pull/105) + ## 4.3.1 (2020-10-30) * Optimize package size by ignoring .idea and .github folders diff --git a/data/features.js b/data/features.js index 860d7d1..bcd15ac 100644 --- a/data/features.js +++ b/data/features.js @@ -1,18 +1,16 @@ var list = require('postcss/lib/list') var pats = { attrcc: '[^\\~|^$*\\]]*', - brackets: /(\[[^\]]*\]|\([^\)]*\))/.source, - nobrackets: /[^\[\]\(\)]/.source + brackets: /\[[^\]]*\]|\([^\)]*\)/g } + function matchOutsideOfBrackets(pat) { if (!(pat instanceof RegExp)) { throw new TypeError('matchOutsideOfBrackets expects a RegExp') } - var fullPat = new RegExp( - '^(' + pats.brackets + '?' + pats.nobrackets + '*)*' + pat.source - ) - return function match(str) { - return pat.test(str) && fullPat.test(str) + + return function(str) { + return pat.test(str.replace(pats.brackets, '')) } } diff --git a/package-lock.json b/package-lock.json index 825e4a8..54bb951 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "doiuse", - "version": "4.2.0", + "version": "4.3.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2899,8 +2899,26 @@ "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "optional": true, + "requires": { + "ret": "~0.1.10" + } + } } }, + "regexp-tree": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.21.tgz", + "integrity": "sha512-kUUXjX4AnqnR8KRTCrayAo9PzYMRKmVoGgaz2tBuz0MF3g1ZbGebmtW0yFHfFK9CmBjQKeYIgoL22pFLBJY7sw==", + "dev": true + }, "regexp.prototype.flags": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", @@ -2998,13 +3016,12 @@ "dev": true }, "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", + "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", "dev": true, - "optional": true, "requires": { - "ret": "~0.1.10" + "regexp-tree": "~0.1.1" } }, "semver": { @@ -3408,6 +3425,18 @@ "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "optional": true, + "requires": { + "ret": "~0.1.10" + } + } } }, "to-regex-range": { diff --git a/package.json b/package.json index 39af242..2ea1bb4 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@babel/core": "^7.12.3", "mock-fs": "^4.13.0", "postcss-import": "^13.0.0", + "safe-regex": "^2.1.1", "tape": "^5.0.1" }, "scripts": { diff --git a/test/regex.js b/test/regex.js new file mode 100644 index 0000000..0380657 --- /dev/null +++ b/test/regex.js @@ -0,0 +1,26 @@ +const test = require('tape') +const safe = require('safe-regex') +const features = require('../data/features') + +regexes = [] + +for (var feature of Object.values(features)) { + for (var property of Object.values(feature)) { + if (!property || !(property instanceof Array)){ + continue; + } + + for (var item of property) { + if (item instanceof RegExp) { + regexes.push(item) + } + } + } +} + +for (var regex of regexes) { + test('Regex safety check: /' + regex.source + '/', function(t) { + t.ok(safe(regex)) + t.end() + }) +}