@@ -50967,8 +50967,11 @@ var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
50967
50967
// Max safe segment length for coercion.
50968
50968
var MAX_SAFE_COMPONENT_LENGTH = 16
50969
50969
50970
+ var MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6
50971
+
50970
50972
// The actual regexps go on exports.re
50971
50973
var re = exports.re = []
50974
+ var safeRe = exports.safeRe = []
50972
50975
var src = exports.src = []
50973
50976
var t = exports.tokens = {}
50974
50977
var R = 0
@@ -50977,6 +50980,31 @@ function tok (n) {
50977
50980
t[n] = R++
50978
50981
}
50979
50982
50983
+ var LETTERDASHNUMBER = '[a-zA-Z0-9-]'
50984
+
50985
+ // Replace some greedy regex tokens to prevent regex dos issues. These regex are
50986
+ // used internally via the safeRe object since all inputs in this library get
50987
+ // normalized first to trim and collapse all extra whitespace. The original
50988
+ // regexes are exported for userland consumption and lower level usage. A
50989
+ // future breaking change could export the safer regex only with a note that
50990
+ // all input should have extra whitespace removed.
50991
+ var safeRegexReplacements = [
50992
+ ['\\s', 1],
50993
+ ['\\d', MAX_LENGTH],
50994
+ [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],
50995
+ ]
50996
+
50997
+ function makeSafeRe (value) {
50998
+ for (var i = 0; i < safeRegexReplacements.length; i++) {
50999
+ var token = safeRegexReplacements[i][0]
51000
+ var max = safeRegexReplacements[i][1]
51001
+ value = value
51002
+ .split(token + '*').join(token + '{0,' + max + '}')
51003
+ .split(token + '+').join(token + '{1,' + max + '}')
51004
+ }
51005
+ return value
51006
+ }
51007
+
50980
51008
// The following Regular Expressions can be used for tokenizing,
50981
51009
// validating, and parsing SemVer version strings.
50982
51010
@@ -50986,14 +51014,14 @@ function tok (n) {
50986
51014
tok('NUMERICIDENTIFIER')
50987
51015
src[t.NUMERICIDENTIFIER] = '0|[1-9]\\d*'
50988
51016
tok('NUMERICIDENTIFIERLOOSE')
50989
- src[t.NUMERICIDENTIFIERLOOSE] = '[0-9] +'
51017
+ src[t.NUMERICIDENTIFIERLOOSE] = '\\d +'
50990
51018
50991
51019
// ## Non-numeric Identifier
50992
51020
// Zero or more digits, followed by a letter or hyphen, and then zero or
50993
51021
// more letters, digits, or hyphens.
50994
51022
50995
51023
tok('NONNUMERICIDENTIFIER')
50996
- src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-] *'
51024
+ src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-]' + LETTERDASHNUMBER + ' *'
50997
51025
50998
51026
// ## Main Version
50999
51027
// Three dot-separated numeric identifiers.
@@ -51035,7 +51063,7 @@ src[t.PRERELEASELOOSE] = '(?:-?(' + src[t.PRERELEASEIDENTIFIERLOOSE] +
51035
51063
// Any combination of digits, letters, or hyphens.
51036
51064
51037
51065
tok('BUILDIDENTIFIER')
51038
- src[t.BUILDIDENTIFIER] = '[0-9A-Za-z-] +'
51066
+ src[t.BUILDIDENTIFIER] = LETTERDASHNUMBER + ' +'
51039
51067
51040
51068
// ## Build Metadata
51041
51069
// Plus sign, followed by one or more period-separated build metadata
@@ -51115,6 +51143,7 @@ src[t.COERCE] = '(^|[^\\d])' +
51115
51143
'(?:$|[^\\d])'
51116
51144
tok('COERCERTL')
51117
51145
re[t.COERCERTL] = new RegExp(src[t.COERCE], 'g')
51146
+ safeRe[t.COERCERTL] = new RegExp(makeSafeRe(src[t.COERCE]), 'g')
51118
51147
51119
51148
// Tilde ranges.
51120
51149
// Meaning is "reasonably at or greater than"
@@ -51124,6 +51153,7 @@ src[t.LONETILDE] = '(?:~>?)'
51124
51153
tok('TILDETRIM')
51125
51154
src[t.TILDETRIM] = '(\\s*)' + src[t.LONETILDE] + '\\s+'
51126
51155
re[t.TILDETRIM] = new RegExp(src[t.TILDETRIM], 'g')
51156
+ safeRe[t.TILDETRIM] = new RegExp(makeSafeRe(src[t.TILDETRIM]), 'g')
51127
51157
var tildeTrimReplace = '$1~'
51128
51158
51129
51159
tok('TILDE')
@@ -51139,6 +51169,7 @@ src[t.LONECARET] = '(?:\\^)'
51139
51169
tok('CARETTRIM')
51140
51170
src[t.CARETTRIM] = '(\\s*)' + src[t.LONECARET] + '\\s+'
51141
51171
re[t.CARETTRIM] = new RegExp(src[t.CARETTRIM], 'g')
51172
+ safeRe[t.CARETTRIM] = new RegExp(makeSafeRe(src[t.CARETTRIM]), 'g')
51142
51173
var caretTrimReplace = '$1^'
51143
51174
51144
51175
tok('CARET')
@@ -51160,6 +51191,7 @@ src[t.COMPARATORTRIM] = '(\\s*)' + src[t.GTLT] +
51160
51191
51161
51192
// this one has to use the /g flag
51162
51193
re[t.COMPARATORTRIM] = new RegExp(src[t.COMPARATORTRIM], 'g')
51194
+ safeRe[t.COMPARATORTRIM] = new RegExp(makeSafeRe(src[t.COMPARATORTRIM]), 'g')
51163
51195
var comparatorTrimReplace = '$1$2$3'
51164
51196
51165
51197
// Something like `1.2.3 - 1.2.4`
@@ -51188,6 +51220,14 @@ for (var i = 0; i < R; i++) {
51188
51220
debug(i, src[i])
51189
51221
if (!re[i]) {
51190
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]))
51191
51231
}
51192
51232
}
51193
51233
@@ -51212,7 +51252,7 @@ function parse (version, options) {
51212
51252
return null
51213
51253
}
51214
51254
51215
- var r = options.loose ? re [t.LOOSE] : re [t.FULL]
51255
+ var r = options.loose ? safeRe [t.LOOSE] : safeRe [t.FULL]
51216
51256
if (!r.test(version)) {
51217
51257
return null
51218
51258
}
@@ -51267,7 +51307,7 @@ function SemVer (version, options) {
51267
51307
this.options = options
51268
51308
this.loose = !!options.loose
51269
51309
51270
- var m = version.trim().match(options.loose ? re [t.LOOSE] : re [t.FULL])
51310
+ var m = version.trim().match(options.loose ? safeRe [t.LOOSE] : safeRe [t.FULL])
51271
51311
51272
51312
if (!m) {
51273
51313
throw new TypeError('Invalid Version: ' + version)
@@ -51712,6 +51752,7 @@ function Comparator (comp, options) {
51712
51752
return new Comparator(comp, options)
51713
51753
}
51714
51754
51755
+ comp = comp.trim().split(/\s+/).join(' ')
51715
51756
debug('comparator', comp, options)
51716
51757
this.options = options
51717
51758
this.loose = !!options.loose
@@ -51728,7 +51769,7 @@ function Comparator (comp, options) {
51728
51769
51729
51770
var ANY = {}
51730
51771
Comparator.prototype.parse = function (comp) {
51731
- var r = this.options.loose ? re [t.COMPARATORLOOSE] : re [t.COMPARATOR]
51772
+ var r = this.options.loose ? safeRe [t.COMPARATORLOOSE] : safeRe [t.COMPARATOR]
51732
51773
var m = comp.match(r)
51733
51774
51734
51775
if (!m) {
@@ -51852,17 +51893,24 @@ function Range (range, options) {
51852
51893
this.loose = !!options.loose
51853
51894
this.includePrerelease = !!options.includePrerelease
51854
51895
51855
- // First, split based on boolean or ||
51896
+ // First reduce all whitespace as much as possible so we do not have to rely
51897
+ // on potentially slow regexes like \s*. This is then stored and used for
51898
+ // future error messages as well.
51856
51899
this.raw = range
51857
- this.set = range.split(/\s*\|\|\s*/).map(function (range) {
51900
+ .trim()
51901
+ .split(/\s+/)
51902
+ .join(' ')
51903
+
51904
+ // First, split based on boolean or ||
51905
+ this.set = this.raw.split('||').map(function (range) {
51858
51906
return this.parseRange(range.trim())
51859
51907
}, this).filter(function (c) {
51860
51908
// throw out any that are not relevant for whatever reason
51861
51909
return c.length
51862
51910
})
51863
51911
51864
51912
if (!this.set.length) {
51865
- throw new TypeError('Invalid SemVer Range: ' + range )
51913
+ throw new TypeError('Invalid SemVer Range: ' + this.raw )
51866
51914
}
51867
51915
51868
51916
this.format()
@@ -51881,28 +51929,27 @@ Range.prototype.toString = function () {
51881
51929
51882
51930
Range.prototype.parseRange = function (range) {
51883
51931
var loose = this.options.loose
51884
- range = range.trim()
51885
51932
// `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
51886
- var hr = loose ? re [t.HYPHENRANGELOOSE] : re [t.HYPHENRANGE]
51933
+ var hr = loose ? safeRe [t.HYPHENRANGELOOSE] : safeRe [t.HYPHENRANGE]
51887
51934
range = range.replace(hr, hyphenReplace)
51888
51935
debug('hyphen replace', range)
51889
51936
// `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
51890
- range = range.replace(re [t.COMPARATORTRIM], comparatorTrimReplace)
51891
- debug('comparator trim', range, re [t.COMPARATORTRIM])
51937
+ range = range.replace(safeRe [t.COMPARATORTRIM], comparatorTrimReplace)
51938
+ debug('comparator trim', range, safeRe [t.COMPARATORTRIM])
51892
51939
51893
51940
// `~ 1.2.3` => `~1.2.3`
51894
- range = range.replace(re [t.TILDETRIM], tildeTrimReplace)
51941
+ range = range.replace(safeRe [t.TILDETRIM], tildeTrimReplace)
51895
51942
51896
51943
// `^ 1.2.3` => `^1.2.3`
51897
- range = range.replace(re [t.CARETTRIM], caretTrimReplace)
51944
+ range = range.replace(safeRe [t.CARETTRIM], caretTrimReplace)
51898
51945
51899
51946
// normalize spaces
51900
51947
range = range.split(/\s+/).join(' ')
51901
51948
51902
51949
// At this point, the range is completely trimmed and
51903
51950
// ready to be split into comparators.
51904
51951
51905
- var compRe = loose ? re [t.COMPARATORLOOSE] : re [t.COMPARATOR]
51952
+ var compRe = loose ? safeRe [t.COMPARATORLOOSE] : safeRe [t.COMPARATOR]
51906
51953
var set = range.split(' ').map(function (comp) {
51907
51954
return parseComparator(comp, this.options)
51908
51955
}, this).join(' ').split(/\s+/)
@@ -52002,7 +52049,7 @@ function replaceTildes (comp, options) {
52002
52049
}
52003
52050
52004
52051
function replaceTilde (comp, options) {
52005
- var r = options.loose ? re [t.TILDELOOSE] : re [t.TILDE]
52052
+ var r = options.loose ? safeRe [t.TILDELOOSE] : safeRe [t.TILDE]
52006
52053
return comp.replace(r, function (_, M, m, p, pr) {
52007
52054
debug('tilde', comp, _, M, m, p, pr)
52008
52055
var ret
@@ -52043,7 +52090,7 @@ function replaceCarets (comp, options) {
52043
52090
52044
52091
function replaceCaret (comp, options) {
52045
52092
debug('caret', comp, options)
52046
- var r = options.loose ? re [t.CARETLOOSE] : re [t.CARET]
52093
+ var r = options.loose ? safeRe [t.CARETLOOSE] : safeRe [t.CARET]
52047
52094
return comp.replace(r, function (_, M, m, p, pr) {
52048
52095
debug('caret', comp, _, M, m, p, pr)
52049
52096
var ret
@@ -52102,7 +52149,7 @@ function replaceXRanges (comp, options) {
52102
52149
52103
52150
function replaceXRange (comp, options) {
52104
52151
comp = comp.trim()
52105
- var r = options.loose ? re [t.XRANGELOOSE] : re [t.XRANGE]
52152
+ var r = options.loose ? safeRe [t.XRANGELOOSE] : safeRe [t.XRANGE]
52106
52153
return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
52107
52154
debug('xRange', comp, ret, gtlt, M, m, p, pr)
52108
52155
var xM = isX(M)
@@ -52177,7 +52224,7 @@ function replaceXRange (comp, options) {
52177
52224
function replaceStars (comp, options) {
52178
52225
debug('replaceStars', comp, options)
52179
52226
// Looseness is ignored here. star is always as loose as it gets!
52180
- return comp.trim().replace(re [t.STAR], '')
52227
+ return comp.trim().replace(safeRe [t.STAR], '')
52181
52228
}
52182
52229
52183
52230
// This function is passed to string.replace(re[t.HYPHENRANGE])
@@ -52503,7 +52550,7 @@ function coerce (version, options) {
52503
52550
52504
52551
var match = null
52505
52552
if (!options.rtl) {
52506
- match = version.match(re [t.COERCE])
52553
+ match = version.match(safeRe [t.COERCE])
52507
52554
} else {
52508
52555
// Find the right-most coercible string that does not share
52509
52556
// a terminus with a more left-ward coercible string.
@@ -52514,17 +52561,17 @@ function coerce (version, options) {
52514
52561
// Stop when we get a match that ends at the string end, since no
52515
52562
// coercible string can be more right-ward without the same terminus.
52516
52563
var next
52517
- while ((next = re [t.COERCERTL].exec(version)) &&
52564
+ while ((next = safeRe [t.COERCERTL].exec(version)) &&
52518
52565
(!match || match.index + match[0].length !== version.length)
52519
52566
) {
52520
52567
if (!match ||
52521
52568
next.index + next[0].length !== match.index + match[0].length) {
52522
52569
match = next
52523
52570
}
52524
- re [t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length
52571
+ safeRe [t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length
52525
52572
}
52526
52573
// leave it in a clean state
52527
- re [t.COERCERTL].lastIndex = -1
52574
+ safeRe [t.COERCERTL].lastIndex = -1
52528
52575
}
52529
52576
52530
52577
if (match === null) {
0 commit comments