@@ -50977,11 +50977,39 @@ var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
50977
50977
// Max safe segment length for coercion.
50978
50978
var MAX_SAFE_COMPONENT_LENGTH = 16
50979
50979
50980
+ var MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6
50981
+
50980
50982
// The actual regexps go on exports.re
50981
50983
var re = exports.re = []
50984
+ var safeRe = exports.safeRe = []
50982
50985
var src = exports.src = []
50983
50986
var R = 0
50984
50987
50988
+ var LETTERDASHNUMBER = '[a-zA-Z0-9-]'
50989
+
50990
+ // Replace some greedy regex tokens to prevent regex dos issues. These regex are
50991
+ // used internally via the safeRe object since all inputs in this library get
50992
+ // normalized first to trim and collapse all extra whitespace. The original
50993
+ // regexes are exported for userland consumption and lower level usage. A
50994
+ // future breaking change could export the safer regex only with a note that
50995
+ // all input should have extra whitespace removed.
50996
+ var safeRegexReplacements = [
50997
+ ['\\s', 1],
50998
+ ['\\d', MAX_LENGTH],
50999
+ [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],
51000
+ ]
51001
+
51002
+ function makeSafeRe (value) {
51003
+ for (var i = 0; i < safeRegexReplacements.length; i++) {
51004
+ var token = safeRegexReplacements[i][0]
51005
+ var max = safeRegexReplacements[i][1]
51006
+ value = value
51007
+ .split(token + '*').join(token + '{0,' + max + '}')
51008
+ .split(token + '+').join(token + '{1,' + max + '}')
51009
+ }
51010
+ return value
51011
+ }
51012
+
50985
51013
// The following Regular Expressions can be used for tokenizing,
50986
51014
// validating, and parsing SemVer version strings.
50987
51015
@@ -50991,14 +51019,14 @@ var R = 0
50991
51019
var NUMERICIDENTIFIER = R++
50992
51020
src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'
50993
51021
var NUMERICIDENTIFIERLOOSE = R++
50994
- src[NUMERICIDENTIFIERLOOSE] = '[0-9] +'
51022
+ src[NUMERICIDENTIFIERLOOSE] = '\\d +'
50995
51023
50996
51024
// ## Non-numeric Identifier
50997
51025
// Zero or more digits, followed by a letter or hyphen, and then zero or
50998
51026
// more letters, digits, or hyphens.
50999
51027
51000
51028
var NONNUMERICIDENTIFIER = R++
51001
- src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-] *'
51029
+ src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-]' + LETTERDASHNUMBER + ' *'
51002
51030
51003
51031
// ## Main Version
51004
51032
// Three dot-separated numeric identifiers.
@@ -51040,7 +51068,7 @@ src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] +
51040
51068
// Any combination of digits, letters, or hyphens.
51041
51069
51042
51070
var BUILDIDENTIFIER = R++
51043
- src[BUILDIDENTIFIER] = '[0-9A-Za-z-] +'
51071
+ src[BUILDIDENTIFIER] = LETTERDASHNUMBER + ' +'
51044
51072
51045
51073
// ## Build Metadata
51046
51074
// Plus sign, followed by one or more period-separated build metadata
@@ -51125,6 +51153,7 @@ src[LONETILDE] = '(?:~>?)'
51125
51153
var TILDETRIM = R++
51126
51154
src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'
51127
51155
re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g')
51156
+ safeRe[TILDETRIM] = new RegExp(makeSafeRe(src[TILDETRIM]), 'g')
51128
51157
var tildeTrimReplace = '$1~'
51129
51158
51130
51159
var TILDE = R++
@@ -51140,6 +51169,7 @@ src[LONECARET] = '(?:\\^)'
51140
51169
var CARETTRIM = R++
51141
51170
src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'
51142
51171
re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g')
51172
+ safeRe[CARETTRIM] = new RegExp(makeSafeRe(src[CARETTRIM]), 'g')
51143
51173
var caretTrimReplace = '$1^'
51144
51174
51145
51175
var CARET = R++
@@ -51161,6 +51191,7 @@ src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] +
51161
51191
51162
51192
// this one has to use the /g flag
51163
51193
re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g')
51194
+ safeRe[COMPARATORTRIM] = new RegExp(makeSafeRe(src[COMPARATORTRIM]), 'g')
51164
51195
var comparatorTrimReplace = '$1$2$3'
51165
51196
51166
51197
// Something like `1.2.3 - 1.2.4`
@@ -51189,6 +51220,14 @@ for (var i = 0; i < R; i++) {
51189
51220
debug(i, src[i])
51190
51221
if (!re[i]) {
51191
51222
re[i] = new RegExp(src[i])
51223
+
51224
+ // Replace all greedy whitespace to prevent regex dos issues. These regex are
51225
+ // used internally via the safeRe object since all inputs in this library get
51226
+ // normalized first to trim and collapse all extra whitespace. The original
51227
+ // regexes are exported for userland consumption and lower level usage. A
51228
+ // future breaking change could export the safer regex only with a note that
51229
+ // all input should have extra whitespace removed.
51230
+ safeRe[i] = new RegExp(makeSafeRe(src[i]))
51192
51231
}
51193
51232
}
51194
51233
@@ -51213,7 +51252,7 @@ function parse (version, options) {
51213
51252
return null
51214
51253
}
51215
51254
51216
- var r = options.loose ? re [LOOSE] : re [FULL]
51255
+ var r = options.loose ? safeRe [LOOSE] : safeRe [FULL]
51217
51256
if (!r.test(version)) {
51218
51257
return null
51219
51258
}
@@ -51268,7 +51307,7 @@ function SemVer (version, options) {
51268
51307
this.options = options
51269
51308
this.loose = !!options.loose
51270
51309
51271
- var m = version.trim().match(options.loose ? re [LOOSE] : re [FULL])
51310
+ var m = version.trim().match(options.loose ? safeRe [LOOSE] : safeRe [FULL])
51272
51311
51273
51312
if (!m) {
51274
51313
throw new TypeError('Invalid Version: ' + version)
@@ -51682,6 +51721,7 @@ function Comparator (comp, options) {
51682
51721
return new Comparator(comp, options)
51683
51722
}
51684
51723
51724
+ comp = comp.trim().split(/\s+/).join(' ')
51685
51725
debug('comparator', comp, options)
51686
51726
this.options = options
51687
51727
this.loose = !!options.loose
@@ -51698,7 +51738,7 @@ function Comparator (comp, options) {
51698
51738
51699
51739
var ANY = {}
51700
51740
Comparator.prototype.parse = function (comp) {
51701
- var r = this.options.loose ? re [COMPARATORLOOSE] : re [COMPARATOR]
51741
+ var r = this.options.loose ? safeRe [COMPARATORLOOSE] : safeRe [COMPARATOR]
51702
51742
var m = comp.match(r)
51703
51743
51704
51744
if (!m) {
@@ -51812,17 +51852,24 @@ function Range (range, options) {
51812
51852
this.loose = !!options.loose
51813
51853
this.includePrerelease = !!options.includePrerelease
51814
51854
51815
- // First, split based on boolean or ||
51855
+ // First reduce all whitespace as much as possible so we do not have to rely
51856
+ // on potentially slow regexes like \s*. This is then stored and used for
51857
+ // future error messages as well.
51816
51858
this.raw = range
51817
- this.set = range.split(/\s*\|\|\s*/).map(function (range) {
51859
+ .trim()
51860
+ .split(/\s+/)
51861
+ .join(' ')
51862
+
51863
+ // First, split based on boolean or ||
51864
+ this.set = this.raw.split('||').map(function (range) {
51818
51865
return this.parseRange(range.trim())
51819
51866
}, this).filter(function (c) {
51820
51867
// throw out any that are not relevant for whatever reason
51821
51868
return c.length
51822
51869
})
51823
51870
51824
51871
if (!this.set.length) {
51825
- throw new TypeError('Invalid SemVer Range: ' + range )
51872
+ throw new TypeError('Invalid SemVer Range: ' + this.raw )
51826
51873
}
51827
51874
51828
51875
this.format()
@@ -51841,28 +51888,23 @@ Range.prototype.toString = function () {
51841
51888
51842
51889
Range.prototype.parseRange = function (range) {
51843
51890
var loose = this.options.loose
51844
- range = range.trim()
51845
51891
// `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
51846
- var hr = loose ? re [HYPHENRANGELOOSE] : re [HYPHENRANGE]
51892
+ var hr = loose ? safeRe [HYPHENRANGELOOSE] : safeRe [HYPHENRANGE]
51847
51893
range = range.replace(hr, hyphenReplace)
51848
51894
debug('hyphen replace', range)
51849
51895
// `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
51850
- range = range.replace(re [COMPARATORTRIM], comparatorTrimReplace)
51851
- debug('comparator trim', range, re [COMPARATORTRIM])
51896
+ range = range.replace(safeRe [COMPARATORTRIM], comparatorTrimReplace)
51897
+ debug('comparator trim', range, safeRe [COMPARATORTRIM])
51852
51898
51853
51899
// `~ 1.2.3` => `~1.2.3`
51854
- range = range.replace(re [TILDETRIM], tildeTrimReplace)
51900
+ range = range.replace(safeRe [TILDETRIM], tildeTrimReplace)
51855
51901
51856
51902
// `^ 1.2.3` => `^1.2.3`
51857
- range = range.replace(re[CARETTRIM], caretTrimReplace)
51858
-
51859
- // normalize spaces
51860
- range = range.split(/\s+/).join(' ')
51903
+ range = range.replace(safeRe[CARETTRIM], caretTrimReplace)
51861
51904
51862
51905
// At this point, the range is completely trimmed and
51863
51906
// ready to be split into comparators.
51864
-
51865
- var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]
51907
+ var compRe = loose ? safeRe[COMPARATORLOOSE] : safeRe[COMPARATOR]
51866
51908
var set = range.split(' ').map(function (comp) {
51867
51909
return parseComparator(comp, this.options)
51868
51910
}, this).join(' ').split(/\s+/)
@@ -51938,7 +51980,7 @@ function replaceTildes (comp, options) {
51938
51980
}
51939
51981
51940
51982
function replaceTilde (comp, options) {
51941
- var r = options.loose ? re [TILDELOOSE] : re [TILDE]
51983
+ var r = options.loose ? safeRe [TILDELOOSE] : safeRe [TILDE]
51942
51984
return comp.replace(r, function (_, M, m, p, pr) {
51943
51985
debug('tilde', comp, _, M, m, p, pr)
51944
51986
var ret
@@ -51979,7 +52021,7 @@ function replaceCarets (comp, options) {
51979
52021
51980
52022
function replaceCaret (comp, options) {
51981
52023
debug('caret', comp, options)
51982
- var r = options.loose ? re [CARETLOOSE] : re [CARET]
52024
+ var r = options.loose ? safeRe [CARETLOOSE] : safeRe [CARET]
51983
52025
return comp.replace(r, function (_, M, m, p, pr) {
51984
52026
debug('caret', comp, _, M, m, p, pr)
51985
52027
var ret
@@ -52038,7 +52080,7 @@ function replaceXRanges (comp, options) {
52038
52080
52039
52081
function replaceXRange (comp, options) {
52040
52082
comp = comp.trim()
52041
- var r = options.loose ? re [XRANGELOOSE] : re [XRANGE]
52083
+ var r = options.loose ? safeRe [XRANGELOOSE] : safeRe [XRANGE]
52042
52084
return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
52043
52085
debug('xRange', comp, ret, gtlt, M, m, p, pr)
52044
52086
var xM = isX(M)
@@ -52108,10 +52150,10 @@ function replaceXRange (comp, options) {
52108
52150
function replaceStars (comp, options) {
52109
52151
debug('replaceStars', comp, options)
52110
52152
// Looseness is ignored here. star is always as loose as it gets!
52111
- return comp.trim().replace(re [STAR], '')
52153
+ return comp.trim().replace(safeRe [STAR], '')
52112
52154
}
52113
52155
52114
- // This function is passed to string.replace(re [HYPHENRANGE])
52156
+ // This function is passed to string.replace(safeRe [HYPHENRANGE])
52115
52157
// M, m, patch, prerelease, build
52116
52158
// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
52117
52159
// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
@@ -52422,7 +52464,7 @@ function coerce (version) {
52422
52464
return null
52423
52465
}
52424
52466
52425
- var match = version.match(re [COERCE])
52467
+ var match = version.match(safeRe [COERCE])
52426
52468
52427
52469
if (match == null) {
52428
52470
return null
0 commit comments