@@ -8,7 +8,9 @@ import * as gestaltsUtils from 'polykey/dist/gestalts/utils';
8
8
import * as networkUtils from 'polykey/dist/network/utils' ;
9
9
import * as nodesUtils from 'polykey/dist/nodes/utils' ;
10
10
11
- const secretPathRegex = / ^ ( [ \w - ] + ) (?: : ( [ ^ \0 \\ = ] + ) ) ? $ / ;
11
+ const vaultNameRegex = / ^ (? ! .* [: ] ) [ - ~ \t \n ] * $ / s;
12
+ const secretPathRegex = / ^ (? ! .* [ = ] ) [ - ~ \t \n ] * $ / s;
13
+ const vaultNameSecretPathRegex = / ^ ( [ \w \- \. ] + ) (?: : ( [ ^ \0 \\ = ] + ) ) ? $ / ;
12
14
const secretPathValueRegex = / ^ ( [ a - z A - Z _ ] [ \w ] + ) ? $ / ;
13
15
const environmentVariableRegex = / ^ ( [ a - z A - Z _ ] + [ a - z A - Z 0 - 9 _ ] * ) ? $ / ;
14
16
@@ -80,15 +82,26 @@ function parseSecretPathOptional(
80
82
lastEqualIndex === - 1
81
83
? undefined
82
84
: secretPath . substring ( lastEqualIndex + 1 ) ;
83
- if ( ! secretPathRegex . test ( splitSecretPath ) ) {
85
+ if ( ! vaultNameSecretPathRegex . test ( splitSecretPath ) ) {
84
86
throw new commander . InvalidArgumentError (
85
87
`${ secretPath } is not of the format <vaultName>[:<directoryPath>][=<value>]` ,
86
88
) ;
87
89
}
88
- const [ , vaultName , directoryPath ] = splitSecretPath . match ( secretPathRegex ) ! ;
90
+ const [ , vaultName , directoryPath ] = splitSecretPath . match (
91
+ vaultNameSecretPathRegex ,
92
+ ) ! ;
89
93
return [ vaultName , directoryPath , value ] ;
90
94
}
91
95
96
+ function parseVaultName ( vaultName : string ) : string {
97
+ if ( ! vaultNameRegex . test ( vaultName ) ) {
98
+ throw new commander . InvalidArgumentError (
99
+ `${ vaultName } is not a valid vault name` ,
100
+ ) ;
101
+ }
102
+ return vaultName ;
103
+ }
104
+
92
105
function parseSecretPath ( secretPath : string ) : [ string , string , string ?] {
93
106
// E.g. If 'vault1:a/b/c', ['vault1', 'a/b/c'] is returned
94
107
// If 'vault1', an error is thrown
@@ -111,8 +124,37 @@ function parseSecretPathValue(secretPath: string): [string, string, string?] {
111
124
return [ vaultName , directoryPath , value ] ;
112
125
}
113
126
114
- function parseSecretPathEnv ( secretPath : string ) : [ string , string , string ?] {
115
- const [ vaultName , directoryPath , value ] = parseSecretPath ( secretPath ) ;
127
+ function parseSecretPathEnv ( secretPath : string ) : [ string , string ?, string ?] {
128
+ // The colon character `:` is prohibited in vaultName, so it's first occurence
129
+ // means that this is the delimiter between vaultName and secretPath.
130
+ const colonIndex = secretPath . indexOf ( ':' ) ;
131
+ // If no colon exists, treat entire string as vault name
132
+ if ( colonIndex === - 1 ) {
133
+ return [ parseVaultName ( secretPath ) , undefined , undefined ] ;
134
+ }
135
+ // Calculate contents before the `=` separator
136
+ const vaultNamePart = secretPath . substring ( 0 , colonIndex ) ;
137
+ const secretPathPart = secretPath . substring ( colonIndex + 1 ) ;
138
+ // Calculate contents after the `=` separator
139
+ const equalIndex = secretPathPart . indexOf ( '=' ) ;
140
+ const splitSecretPath =
141
+ equalIndex === - 1
142
+ ? secretPathPart
143
+ : secretPathPart . substring ( 0 , equalIndex ) ;
144
+ const valueData =
145
+ equalIndex === - 1 ? undefined : secretPathPart . substring ( equalIndex + 1 ) ;
146
+ if ( splitSecretPath != null && ! secretPathRegex . test ( splitSecretPath ) ) {
147
+ throw new commander . InvalidArgumentError (
148
+ `${ secretPath } is not of the format <vaultName>[:<secretPath>][=<value>]` ,
149
+ ) ;
150
+ }
151
+ const parsedVaultName = parseVaultName ( vaultNamePart ) ;
152
+ const parsedSecretPath = splitSecretPath . match ( secretPathRegex ) ?. [ 0 ] ?? '/' ;
153
+ const [ vaultName , directoryPath , value ] = [
154
+ parsedVaultName ,
155
+ parsedSecretPath ,
156
+ valueData ,
157
+ ] ;
116
158
if ( value != null && ! environmentVariableRegex . test ( value ) ) {
117
159
throw new commander . InvalidArgumentError (
118
160
`${ value } is not a valid environment variable name` ,
@@ -182,25 +224,24 @@ const parseSeedNodes: (data: string) => [SeedNodes, boolean] =
182
224
183
225
/**
184
226
* This parses the arguments used for the env command. It should be formatted as
185
- * <secretPath...> [--] [ cmd] [cmdArgs...]
186
- * The cmd part of the list is separated in two ways, either the user explicitly uses `--` or the first non-secret path separates it .
227
+ * <secretPath...> [-- cmd [cmdArgs...] ]
228
+ * The cmd part of the list is separated by using `--`.
187
229
*/
188
230
function parseEnvArgs (
189
231
value : string ,
190
- prev : [ Array < [ string , string , string ?] > , Array < string > ] | undefined ,
191
- ) : [ Array < [ string , string , string ?] > , Array < string > ] {
192
- const current : [ Array < [ string , string , string ?] > , Array < string > ] = prev ?? [
232
+ prev : [ Array < [ string , string ? , string ?] > , Array < string > ] | undefined ,
233
+ ) : [ Array < [ string , string ? , string ?] > , Array < string > ] {
234
+ const current : [ Array < [ string , string ? , string ?] > , Array < string > ] = prev ?? [
193
235
[ ] ,
194
236
[ ] ,
195
237
] ;
196
238
if ( current [ 1 ] . length === 0 ) {
197
239
// Parse a secret path
198
- try {
240
+ if ( value !== '--' ) {
199
241
current [ 0 ] . push ( parseSecretPathEnv ( value ) ) ;
200
- } catch ( e ) {
201
- if ( ! ( e instanceof commander . InvalidArgumentError ) ) throw e ;
202
- // If we get an invalid argument error then we switch over to parsing args verbatim
242
+ } else {
203
243
current [ 1 ] . push ( value ) ;
244
+ return current ;
204
245
}
205
246
} else {
206
247
// Otherwise we just have the cmd args
@@ -215,13 +256,15 @@ function parseEnvArgs(
215
256
}
216
257
217
258
export {
259
+ vaultNameRegex ,
218
260
secretPathRegex ,
219
261
secretPathValueRegex ,
220
262
environmentVariableRegex ,
221
263
validateParserToArgParser ,
222
264
validateParserToArgListParser ,
223
265
parseCoreCount ,
224
266
parseSecretPathOptional ,
267
+ parseVaultName ,
225
268
parseSecretPath ,
226
269
parseSecretPathValue ,
227
270
parseSecretPathEnv ,
0 commit comments