@@ -51331,8 +51331,11 @@ var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
51331
51331
// Max safe segment length for coercion.
51332
51332
var MAX_SAFE_COMPONENT_LENGTH = 16
51333
51333
51334
+ var MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6
51335
+
51334
51336
// The actual regexps go on exports.re
51335
51337
var re = exports.re = []
51338
+ var safeRe = exports.safeRe = []
51336
51339
var src = exports.src = []
51337
51340
var t = exports.tokens = {}
51338
51341
var R = 0
@@ -51341,6 +51344,31 @@ function tok (n) {
51341
51344
t[n] = R++
51342
51345
}
51343
51346
51347
+ var LETTERDASHNUMBER = '[a-zA-Z0-9-]'
51348
+
51349
+ // Replace some greedy regex tokens to prevent regex dos issues. These regex are
51350
+ // used internally via the safeRe object since all inputs in this library get
51351
+ // normalized first to trim and collapse all extra whitespace. The original
51352
+ // regexes are exported for userland consumption and lower level usage. A
51353
+ // future breaking change could export the safer regex only with a note that
51354
+ // all input should have extra whitespace removed.
51355
+ var safeRegexReplacements = [
51356
+ ['\\s', 1],
51357
+ ['\\d', MAX_LENGTH],
51358
+ [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],
51359
+ ]
51360
+
51361
+ function makeSafeRe (value) {
51362
+ for (var i = 0; i < safeRegexReplacements.length; i++) {
51363
+ var token = safeRegexReplacements[i][0]
51364
+ var max = safeRegexReplacements[i][1]
51365
+ value = value
51366
+ .split(token + '*').join(token + '{0,' + max + '}')
51367
+ .split(token + '+').join(token + '{1,' + max + '}')
51368
+ }
51369
+ return value
51370
+ }
51371
+
51344
51372
// The following Regular Expressions can be used for tokenizing,
51345
51373
// validating, and parsing SemVer version strings.
51346
51374
@@ -51350,14 +51378,14 @@ function tok (n) {
51350
51378
tok('NUMERICIDENTIFIER')
51351
51379
src[t.NUMERICIDENTIFIER] = '0|[1-9]\\d*'
51352
51380
tok('NUMERICIDENTIFIERLOOSE')
51353
- src[t.NUMERICIDENTIFIERLOOSE] = '[0-9] +'
51381
+ src[t.NUMERICIDENTIFIERLOOSE] = '\\d +'
51354
51382
51355
51383
// ## Non-numeric Identifier
51356
51384
// Zero or more digits, followed by a letter or hyphen, and then zero or
51357
51385
// more letters, digits, or hyphens.
51358
51386
51359
51387
tok('NONNUMERICIDENTIFIER')
51360
- src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-] *'
51388
+ src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-]' + LETTERDASHNUMBER + ' *'
51361
51389
51362
51390
// ## Main Version
51363
51391
// Three dot-separated numeric identifiers.
@@ -51399,7 +51427,7 @@ src[t.PRERELEASELOOSE] = '(?:-?(' + src[t.PRERELEASEIDENTIFIERLOOSE] +
51399
51427
// Any combination of digits, letters, or hyphens.
51400
51428
51401
51429
tok('BUILDIDENTIFIER')
51402
- src[t.BUILDIDENTIFIER] = '[0-9A-Za-z-] +'
51430
+ src[t.BUILDIDENTIFIER] = LETTERDASHNUMBER + ' +'
51403
51431
51404
51432
// ## Build Metadata
51405
51433
// Plus sign, followed by one or more period-separated build metadata
@@ -51479,6 +51507,7 @@ src[t.COERCE] = '(^|[^\\d])' +
51479
51507
'(?:$|[^\\d])'
51480
51508
tok('COERCERTL')
51481
51509
re[t.COERCERTL] = new RegExp(src[t.COERCE], 'g')
51510
+ safeRe[t.COERCERTL] = new RegExp(makeSafeRe(src[t.COERCE]), 'g')
51482
51511
51483
51512
// Tilde ranges.
51484
51513
// Meaning is "reasonably at or greater than"
@@ -51488,6 +51517,7 @@ src[t.LONETILDE] = '(?:~>?)'
51488
51517
tok('TILDETRIM')
51489
51518
src[t.TILDETRIM] = '(\\s*)' + src[t.LONETILDE] + '\\s+'
51490
51519
re[t.TILDETRIM] = new RegExp(src[t.TILDETRIM], 'g')
51520
+ safeRe[t.TILDETRIM] = new RegExp(makeSafeRe(src[t.TILDETRIM]), 'g')
51491
51521
var tildeTrimReplace = '$1~'
51492
51522
51493
51523
tok('TILDE')
@@ -51503,6 +51533,7 @@ src[t.LONECARET] = '(?:\\^)'
51503
51533
tok('CARETTRIM')
51504
51534
src[t.CARETTRIM] = '(\\s*)' + src[t.LONECARET] + '\\s+'
51505
51535
re[t.CARETTRIM] = new RegExp(src[t.CARETTRIM], 'g')
51536
+ safeRe[t.CARETTRIM] = new RegExp(makeSafeRe(src[t.CARETTRIM]), 'g')
51506
51537
var caretTrimReplace = '$1^'
51507
51538
51508
51539
tok('CARET')
@@ -51524,6 +51555,7 @@ src[t.COMPARATORTRIM] = '(\\s*)' + src[t.GTLT] +
51524
51555
51525
51556
// this one has to use the /g flag
51526
51557
re[t.COMPARATORTRIM] = new RegExp(src[t.COMPARATORTRIM], 'g')
51558
+ safeRe[t.COMPARATORTRIM] = new RegExp(makeSafeRe(src[t.COMPARATORTRIM]), 'g')
51527
51559
var comparatorTrimReplace = '$1$2$3'
51528
51560
51529
51561
// Something like `1.2.3 - 1.2.4`
@@ -51552,6 +51584,14 @@ for (var i = 0; i < R; i++) {
51552
51584
debug(i, src[i])
51553
51585
if (!re[i]) {
51554
51586
re[i] = new RegExp(src[i])
51587
+
51588
+ // Replace all greedy whitespace to prevent regex dos issues. These regex are
51589
+ // used internally via the safeRe object since all inputs in this library get
51590
+ // normalized first to trim and collapse all extra whitespace. The original
51591
+ // regexes are exported for userland consumption and lower level usage. A
51592
+ // future breaking change could export the safer regex only with a note that
51593
+ // all input should have extra whitespace removed.
51594
+ safeRe[i] = new RegExp(makeSafeRe(src[i]))
51555
51595
}
51556
51596
}
51557
51597
@@ -51576,7 +51616,7 @@ function parse (version, options) {
51576
51616
return null
51577
51617
}
51578
51618
51579
- var r = options.loose ? re [t.LOOSE] : re [t.FULL]
51619
+ var r = options.loose ? safeRe [t.LOOSE] : safeRe [t.FULL]
51580
51620
if (!r.test(version)) {
51581
51621
return null
51582
51622
}
@@ -51631,7 +51671,7 @@ function SemVer (version, options) {
51631
51671
this.options = options
51632
51672
this.loose = !!options.loose
51633
51673
51634
- var m = version.trim().match(options.loose ? re [t.LOOSE] : re [t.FULL])
51674
+ var m = version.trim().match(options.loose ? safeRe [t.LOOSE] : safeRe [t.FULL])
51635
51675
51636
51676
if (!m) {
51637
51677
throw new TypeError('Invalid Version: ' + version)
@@ -52076,6 +52116,7 @@ function Comparator (comp, options) {
52076
52116
return new Comparator(comp, options)
52077
52117
}
52078
52118
52119
+ comp = comp.trim().split(/\s+/).join(' ')
52079
52120
debug('comparator', comp, options)
52080
52121
this.options = options
52081
52122
this.loose = !!options.loose
@@ -52092,7 +52133,7 @@ function Comparator (comp, options) {
52092
52133
52093
52134
var ANY = {}
52094
52135
Comparator.prototype.parse = function (comp) {
52095
- var r = this.options.loose ? re [t.COMPARATORLOOSE] : re [t.COMPARATOR]
52136
+ var r = this.options.loose ? safeRe [t.COMPARATORLOOSE] : safeRe [t.COMPARATOR]
52096
52137
var m = comp.match(r)
52097
52138
52098
52139
if (!m) {
@@ -52216,17 +52257,24 @@ function Range (range, options) {
52216
52257
this.loose = !!options.loose
52217
52258
this.includePrerelease = !!options.includePrerelease
52218
52259
52219
- // First, split based on boolean or ||
52260
+ // First reduce all whitespace as much as possible so we do not have to rely
52261
+ // on potentially slow regexes like \s*. This is then stored and used for
52262
+ // future error messages as well.
52220
52263
this.raw = range
52221
- this.set = range.split(/\s*\|\|\s*/).map(function (range) {
52264
+ .trim()
52265
+ .split(/\s+/)
52266
+ .join(' ')
52267
+
52268
+ // First, split based on boolean or ||
52269
+ this.set = this.raw.split('||').map(function (range) {
52222
52270
return this.parseRange(range.trim())
52223
52271
}, this).filter(function (c) {
52224
52272
// throw out any that are not relevant for whatever reason
52225
52273
return c.length
52226
52274
})
52227
52275
52228
52276
if (!this.set.length) {
52229
- throw new TypeError('Invalid SemVer Range: ' + range )
52277
+ throw new TypeError('Invalid SemVer Range: ' + this.raw )
52230
52278
}
52231
52279
52232
52280
this.format()
@@ -52245,28 +52293,27 @@ Range.prototype.toString = function () {
52245
52293
52246
52294
Range.prototype.parseRange = function (range) {
52247
52295
var loose = this.options.loose
52248
- range = range.trim()
52249
52296
// `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
52250
- var hr = loose ? re [t.HYPHENRANGELOOSE] : re [t.HYPHENRANGE]
52297
+ var hr = loose ? safeRe [t.HYPHENRANGELOOSE] : safeRe [t.HYPHENRANGE]
52251
52298
range = range.replace(hr, hyphenReplace)
52252
52299
debug('hyphen replace', range)
52253
52300
// `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
52254
- range = range.replace(re [t.COMPARATORTRIM], comparatorTrimReplace)
52255
- debug('comparator trim', range, re [t.COMPARATORTRIM])
52301
+ range = range.replace(safeRe [t.COMPARATORTRIM], comparatorTrimReplace)
52302
+ debug('comparator trim', range, safeRe [t.COMPARATORTRIM])
52256
52303
52257
52304
// `~ 1.2.3` => `~1.2.3`
52258
- range = range.replace(re [t.TILDETRIM], tildeTrimReplace)
52305
+ range = range.replace(safeRe [t.TILDETRIM], tildeTrimReplace)
52259
52306
52260
52307
// `^ 1.2.3` => `^1.2.3`
52261
- range = range.replace(re [t.CARETTRIM], caretTrimReplace)
52308
+ range = range.replace(safeRe [t.CARETTRIM], caretTrimReplace)
52262
52309
52263
52310
// normalize spaces
52264
52311
range = range.split(/\s+/).join(' ')
52265
52312
52266
52313
// At this point, the range is completely trimmed and
52267
52314
// ready to be split into comparators.
52268
52315
52269
- var compRe = loose ? re [t.COMPARATORLOOSE] : re [t.COMPARATOR]
52316
+ var compRe = loose ? safeRe [t.COMPARATORLOOSE] : safeRe [t.COMPARATOR]
52270
52317
var set = range.split(' ').map(function (comp) {
52271
52318
return parseComparator(comp, this.options)
52272
52319
}, this).join(' ').split(/\s+/)
@@ -52366,7 +52413,7 @@ function replaceTildes (comp, options) {
52366
52413
}
52367
52414
52368
52415
function replaceTilde (comp, options) {
52369
- var r = options.loose ? re [t.TILDELOOSE] : re [t.TILDE]
52416
+ var r = options.loose ? safeRe [t.TILDELOOSE] : safeRe [t.TILDE]
52370
52417
return comp.replace(r, function (_, M, m, p, pr) {
52371
52418
debug('tilde', comp, _, M, m, p, pr)
52372
52419
var ret
@@ -52407,7 +52454,7 @@ function replaceCarets (comp, options) {
52407
52454
52408
52455
function replaceCaret (comp, options) {
52409
52456
debug('caret', comp, options)
52410
- var r = options.loose ? re [t.CARETLOOSE] : re [t.CARET]
52457
+ var r = options.loose ? safeRe [t.CARETLOOSE] : safeRe [t.CARET]
52411
52458
return comp.replace(r, function (_, M, m, p, pr) {
52412
52459
debug('caret', comp, _, M, m, p, pr)
52413
52460
var ret
@@ -52466,7 +52513,7 @@ function replaceXRanges (comp, options) {
52466
52513
52467
52514
function replaceXRange (comp, options) {
52468
52515
comp = comp.trim()
52469
- var r = options.loose ? re [t.XRANGELOOSE] : re [t.XRANGE]
52516
+ var r = options.loose ? safeRe [t.XRANGELOOSE] : safeRe [t.XRANGE]
52470
52517
return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
52471
52518
debug('xRange', comp, ret, gtlt, M, m, p, pr)
52472
52519
var xM = isX(M)
@@ -52541,7 +52588,7 @@ function replaceXRange (comp, options) {
52541
52588
function replaceStars (comp, options) {
52542
52589
debug('replaceStars', comp, options)
52543
52590
// Looseness is ignored here. star is always as loose as it gets!
52544
- return comp.trim().replace(re [t.STAR], '')
52591
+ return comp.trim().replace(safeRe [t.STAR], '')
52545
52592
}
52546
52593
52547
52594
// This function is passed to string.replace(re[t.HYPHENRANGE])
@@ -52867,7 +52914,7 @@ function coerce (version, options) {
52867
52914
52868
52915
var match = null
52869
52916
if (!options.rtl) {
52870
- match = version.match(re [t.COERCE])
52917
+ match = version.match(safeRe [t.COERCE])
52871
52918
} else {
52872
52919
// Find the right-most coercible string that does not share
52873
52920
// a terminus with a more left-ward coercible string.
@@ -52878,17 +52925,17 @@ function coerce (version, options) {
52878
52925
// Stop when we get a match that ends at the string end, since no
52879
52926
// coercible string can be more right-ward without the same terminus.
52880
52927
var next
52881
- while ((next = re [t.COERCERTL].exec(version)) &&
52928
+ while ((next = safeRe [t.COERCERTL].exec(version)) &&
52882
52929
(!match || match.index + match[0].length !== version.length)
52883
52930
) {
52884
52931
if (!match ||
52885
52932
next.index + next[0].length !== match.index + match[0].length) {
52886
52933
match = next
52887
52934
}
52888
- re [t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length
52935
+ safeRe [t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length
52889
52936
}
52890
52937
// leave it in a clean state
52891
- re [t.COERCERTL].lastIndex = -1
52938
+ safeRe [t.COERCERTL].lastIndex = -1
52892
52939
}
52893
52940
52894
52941
if (match === null) {
0 commit comments