1- const { MAX_SAFE_COMPONENT_LENGTH } = require ( './constants' )
1+ const { MAX_SAFE_COMPONENT_LENGTH , MAX_SAFE_BUILD_LENGTH } = require ( './constants' )
22const debug = require ( './debug' )
33exports = module . exports = { }
44
@@ -9,16 +9,31 @@ const src = exports.src = []
99const t = exports . t = { }
1010let R = 0
1111
12+ const LETTERDASHNUMBER = '[a-zA-Z0-9-]'
13+
14+ // Replace some greedy regex tokens to prevent regex dos issues. These regex are
15+ // used internally via the safeRe object since all inputs in this library get
16+ // normalized first to trim and collapse all extra whitespace. The original
17+ // regexes are exported for userland consumption and lower level usage. A
18+ // future breaking change could export the safer regex only with a note that
19+ // all input should have extra whitespace removed.
20+ const safeRegexReplacements = [
21+ [ '\\s' , 1 ] ,
22+ [ '\\d' , MAX_SAFE_COMPONENT_LENGTH ] ,
23+ [ LETTERDASHNUMBER , MAX_SAFE_BUILD_LENGTH ] ,
24+ ]
25+
26+ const makeSafeRegex = ( value ) => {
27+ for ( const [ token , max ] of safeRegexReplacements ) {
28+ value = value
29+ . split ( `${ token } *` ) . join ( `${ token } {0,${ max } }` )
30+ . split ( `${ token } +` ) . join ( `${ token } {1,${ max } }` )
31+ }
32+ return value
33+ }
34+
1235const createToken = ( name , value , isGlobal ) => {
13- // Replace all greedy whitespace to prevent regex dos issues. These regex are
14- // used internally via the safeRe object since all inputs in this library get
15- // normalized first to trim and collapse all extra whitespace. The original
16- // regexes are exported for userland consumption and lower level usage. A
17- // future breaking change could export the safer regex only with a note that
18- // all input should have extra whitespace removed.
19- const safe = value
20- . split ( '\\s*' ) . join ( '\\s{0,1}' )
21- . split ( '\\s+' ) . join ( '\\s' )
36+ const safe = makeSafeRegex ( value )
2237 const index = R ++
2338 debug ( name , index , value )
2439 t [ name ] = index
@@ -34,13 +49,13 @@ const createToken = (name, value, isGlobal) => {
3449// A single `0`, or a non-zero digit followed by zero or more digits.
3550
3651createToken ( 'NUMERICIDENTIFIER' , '0|[1-9]\\d*' )
37- createToken ( 'NUMERICIDENTIFIERLOOSE' , '[0-9] +' )
52+ createToken ( 'NUMERICIDENTIFIERLOOSE' , '\\d +' )
3853
3954// ## Non-numeric Identifier
4055// Zero or more digits, followed by a letter or hyphen, and then zero or
4156// more letters, digits, or hyphens.
4257
43- createToken ( 'NONNUMERICIDENTIFIER' , ' \\d*[a-zA-Z-][a-zA-Z0-9-]*' )
58+ createToken ( 'NONNUMERICIDENTIFIER' , ` \\d*[a-zA-Z-]${ LETTERDASHNUMBER } *` )
4459
4560// ## Main Version
4661// Three dot-separated numeric identifiers.
@@ -75,7 +90,7 @@ createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]
7590// ## Build Metadata Identifier
7691// Any combination of digits, letters, or hyphens.
7792
78- createToken ( 'BUILDIDENTIFIER' , '[0-9A-Za-z-]+' )
93+ createToken ( 'BUILDIDENTIFIER' , ` ${ LETTERDASHNUMBER } +` )
7994
8095// ## Build Metadata
8196// Plus sign, followed by one or more period-separated build metadata
0 commit comments