1
- const { MAX_SAFE_COMPONENT_LENGTH } = require ( './constants' )
1
+ const {
2
+ MAX_SAFE_COMPONENT_LENGTH ,
3
+ MAX_SAFE_BUILD_LENGTH ,
4
+ MAX_LENGTH ,
5
+ } = require ( './constants' )
2
6
const debug = require ( './debug' )
3
7
exports = module . exports = { }
4
8
@@ -9,16 +13,31 @@ const src = exports.src = []
9
13
const t = exports . t = { }
10
14
let R = 0
11
15
16
+ const LETTERDASHNUMBER = '[a-zA-Z0-9-]'
17
+
18
+ // Replace some greedy regex tokens to prevent regex dos issues. These regex are
19
+ // used internally via the safeRe object since all inputs in this library get
20
+ // normalized first to trim and collapse all extra whitespace. The original
21
+ // regexes are exported for userland consumption and lower level usage. A
22
+ // future breaking change could export the safer regex only with a note that
23
+ // all input should have extra whitespace removed.
24
+ const safeRegexReplacements = [
25
+ [ '\\s' , 1 ] ,
26
+ [ '\\d' , MAX_LENGTH ] ,
27
+ [ LETTERDASHNUMBER , MAX_SAFE_BUILD_LENGTH ] ,
28
+ ]
29
+
30
+ const makeSafeRegex = ( value ) => {
31
+ for ( const [ token , max ] of safeRegexReplacements ) {
32
+ value = value
33
+ . split ( `${ token } *` ) . join ( `${ token } {0,${ max } }` )
34
+ . split ( `${ token } +` ) . join ( `${ token } {1,${ max } }` )
35
+ }
36
+ return value
37
+ }
38
+
12
39
const 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' )
40
+ const safe = makeSafeRegex ( value )
22
41
const index = R ++
23
42
debug ( name , index , value )
24
43
t [ name ] = index
@@ -34,13 +53,13 @@ const createToken = (name, value, isGlobal) => {
34
53
// A single `0`, or a non-zero digit followed by zero or more digits.
35
54
36
55
createToken ( 'NUMERICIDENTIFIER' , '0|[1-9]\\d*' )
37
- createToken ( 'NUMERICIDENTIFIERLOOSE' , '[0-9] +' )
56
+ createToken ( 'NUMERICIDENTIFIERLOOSE' , '\\d +' )
38
57
39
58
// ## Non-numeric Identifier
40
59
// Zero or more digits, followed by a letter or hyphen, and then zero or
41
60
// more letters, digits, or hyphens.
42
61
43
- createToken ( 'NONNUMERICIDENTIFIER' , ' \\d*[a-zA-Z-][a-zA-Z0-9-]*' )
62
+ createToken ( 'NONNUMERICIDENTIFIER' , ` \\d*[a-zA-Z-]${ LETTERDASHNUMBER } *` )
44
63
45
64
// ## Main Version
46
65
// Three dot-separated numeric identifiers.
@@ -75,7 +94,7 @@ createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]
75
94
// ## Build Metadata Identifier
76
95
// Any combination of digits, letters, or hyphens.
77
96
78
- createToken ( 'BUILDIDENTIFIER' , '[0-9A-Za-z-]+' )
97
+ createToken ( 'BUILDIDENTIFIER' , ` ${ LETTERDASHNUMBER } +` )
79
98
80
99
// ## Build Metadata
81
100
// Plus sign, followed by one or more period-separated build metadata
0 commit comments