@@ -206,7 +206,11 @@ func configSSH() *cobra.Command {
206
206
// Parse the previous configuration only if config-ssh
207
207
// has been run previously.
208
208
var lastConfig * sshConfigOptions
209
- if section , ok := sshConfigGetCoderSection (configRaw ); ok {
209
+ section , ok , err := sshConfigGetCoderSection (configRaw )
210
+ if err != nil {
211
+ return err
212
+ }
213
+ if ok {
210
214
c := sshConfigParseLastOptions (bytes .NewReader (section ))
211
215
lastConfig = & c
212
216
}
@@ -249,7 +253,10 @@ func configSSH() *cobra.Command {
249
253
configModified := configRaw
250
254
251
255
buf := & bytes.Buffer {}
252
- before , after := sshConfigSplitOnCoderSection (configModified )
256
+ before , _ , after , err := sshConfigSplitOnCoderSection (configModified )
257
+ if err != nil {
258
+ return err
259
+ }
253
260
// Write the first half of the users config file to buf.
254
261
_ , _ = buf .Write (before )
255
262
@@ -418,22 +425,39 @@ func sshConfigParseLastOptions(r io.Reader) (o sshConfigOptions) {
418
425
return o
419
426
}
420
427
421
- func sshConfigGetCoderSection (data []byte ) (section []byte , ok bool ) {
422
- startIndex := bytes .Index (data , []byte (sshStartToken ))
423
- endIndex := bytes .Index (data , []byte (sshEndToken ))
424
- if startIndex != - 1 && endIndex != - 1 {
425
- return data [startIndex : endIndex + len (sshEndToken )], true
428
+ // sshConfigGetCoderSection is a helper function that only returns the coder
429
+ // section of the SSH config and a boolean if it exists.
430
+ func sshConfigGetCoderSection (data []byte ) (section []byte , ok bool , err error ) {
431
+ _ , section , _ , err = sshConfigSplitOnCoderSection (data )
432
+ if err != nil {
433
+ return nil , false , err
426
434
}
427
- return nil , false
435
+
436
+ return section , len (section ) > 0 , nil
428
437
}
429
438
430
- // sshConfigSplitOnCoderSection splits the SSH config into two sections,
431
- // before contains the lines before sshStartToken and after contains the
432
- // lines after sshEndToken.
433
- func sshConfigSplitOnCoderSection (data []byte ) (before , after []byte ) {
439
+ // sshConfigSplitOnCoderSection splits the SSH config into 3 sections.
440
+ // All lines before sshStartToken, the coder section, and all lines after
441
+ // sshEndToken.
442
+ func sshConfigSplitOnCoderSection (data []byte ) (before , section []byte , after []byte , err error ) {
443
+ startCount := bytes .Count (data , []byte (sshStartToken ))
444
+ endCount := bytes .Count (data , []byte (sshEndToken ))
445
+ if startCount > 1 || endCount > 1 {
446
+ return nil , nil , nil , xerrors .New ("Malformed config: ssh config has multiple coder sections, please remove all but one" )
447
+ }
448
+
434
449
startIndex := bytes .Index (data , []byte (sshStartToken ))
435
450
endIndex := bytes .Index (data , []byte (sshEndToken ))
451
+ if startIndex == - 1 && endIndex != - 1 {
452
+ return nil , nil , nil , xerrors .New ("Malformed config: ssh config has end header, but missing start header" )
453
+ }
454
+ if startIndex != - 1 && endIndex == - 1 {
455
+ return nil , nil , nil , xerrors .New ("Malformed config: ssh config has start header, but missing end header" )
456
+ }
436
457
if startIndex != - 1 && endIndex != - 1 {
458
+ if startIndex > endIndex {
459
+ return nil , nil , nil , xerrors .New ("Malformed config: ssh config has coder section, but it is malformed and the END header is before the START header" )
460
+ }
437
461
// We use -1 and +1 here to also include the preceding
438
462
// and trailing newline, where applicable.
439
463
start := startIndex
@@ -444,10 +468,10 @@ func sshConfigSplitOnCoderSection(data []byte) (before, after []byte) {
444
468
if end < len (data ) {
445
469
end ++
446
470
}
447
- return data [:start ], data [end :]
471
+ return data [:start ], data [start : end ], data [ end :], nil
448
472
}
449
473
450
- return data , nil
474
+ return data , nil , nil , nil
451
475
}
452
476
453
477
// writeWithTempFileAndMove writes to a temporary file in the same
0 commit comments