@@ -8,7 +8,9 @@ import * as gestaltsUtils from 'polykey/dist/gestalts/utils';
88import * as networkUtils from 'polykey/dist/network/utils' ;
99import * as nodesUtils from 'polykey/dist/nodes/utils' ;
1010
11- const secretPathRegex = / ^ ( [ \w - ] + ) (?: : ( [ ^ \0 \\ = ] + ) ) ? $ / ;
11+ const vaultNameRegex = / ^ (? ! .* [: ] ) [ - ~ \t \n ] * $ / s;
12+ const secretPathRegex = / ^ (? ! .* [ = ] ) [ - ~ \t \n ] * $ / s;
13+ const vaultNameSecretPathRegex = / ^ ( [ \w \- \. ] + ) (?: : ( [ ^ \0 \\ = ] + ) ) ? $ / ;
1214const secretPathValueRegex = / ^ ( [ a - z A - Z _ ] [ \w ] + ) ? $ / ;
1315const environmentVariableRegex = / ^ ( [ a - z A - Z _ ] + [ a - z A - Z 0 - 9 _ ] * ) ? $ / ;
1416
@@ -80,15 +82,26 @@ function parseSecretPathOptional(
8082 lastEqualIndex === - 1
8183 ? undefined
8284 : secretPath . substring ( lastEqualIndex + 1 ) ;
83- if ( ! secretPathRegex . test ( splitSecretPath ) ) {
85+ if ( ! vaultNameSecretPathRegex . test ( splitSecretPath ) ) {
8486 throw new commander . InvalidArgumentError (
8587 `${ secretPath } is not of the format <vaultName>[:<directoryPath>][=<value>]` ,
8688 ) ;
8789 }
88- const [ , vaultName , directoryPath ] = splitSecretPath . match ( secretPathRegex ) ! ;
90+ const [ , vaultName , directoryPath ] = splitSecretPath . match (
91+ vaultNameSecretPathRegex ,
92+ ) ! ;
8993 return [ vaultName , directoryPath , value ] ;
9094}
9195
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+
92105function parseSecretPath ( secretPath : string ) : [ string , string , string ?] {
93106 // E.g. If 'vault1:a/b/c', ['vault1', 'a/b/c'] is returned
94107 // If 'vault1', an error is thrown
@@ -111,8 +124,37 @@ function parseSecretPathValue(secretPath: string): [string, string, string?] {
111124 return [ vaultName , directoryPath , value ] ;
112125}
113126
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+ ] ;
116158 if ( value != null && ! environmentVariableRegex . test ( value ) ) {
117159 throw new commander . InvalidArgumentError (
118160 `${ value } is not a valid environment variable name` ,
@@ -182,25 +224,24 @@ const parseSeedNodes: (data: string) => [SeedNodes, boolean] =
182224
183225/**
184226 * 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 `--`.
187229 */
188230function parseEnvArgs (
189231 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 ?? [
193235 [ ] ,
194236 [ ] ,
195237 ] ;
196238 if ( current [ 1 ] . length === 0 ) {
197239 // Parse a secret path
198- try {
240+ if ( value !== '--' ) {
199241 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 {
203243 current [ 1 ] . push ( value ) ;
244+ return current ;
204245 }
205246 } else {
206247 // Otherwise we just have the cmd args
@@ -215,13 +256,15 @@ function parseEnvArgs(
215256}
216257
217258export {
259+ vaultNameRegex ,
218260 secretPathRegex ,
219261 secretPathValueRegex ,
220262 environmentVariableRegex ,
221263 validateParserToArgParser ,
222264 validateParserToArgListParser ,
223265 parseCoreCount ,
224266 parseSecretPathOptional ,
267+ parseVaultName ,
225268 parseSecretPath ,
226269 parseSecretPathValue ,
227270 parseSecretPathEnv ,
0 commit comments