@@ -19,6 +19,7 @@ import (
1919 "archive/zip"
2020 "encoding/json"
2121 "fmt"
22+ "github.com/hashicorp/go-multierror"
2223 "io"
2324 "io/ioutil"
2425 "net/http"
@@ -314,11 +315,12 @@ func DownloadStarterProjectAsDir(path string, registryURL string, stack string,
314315 defer archive .Close ()
315316
316317 // Extract files from starter project archive to specified directory path
318+ cleanPath := filepath .Clean (path )
317319 for _ , file := range archive .File {
318- filePath := filepath .Join (path , file .Name )
320+ filePath := filepath .Join (cleanPath , filepath . Clean ( file .Name ) )
319321
320322 // validate extracted filepath
321- if filePath != file .Name && ! strings .HasPrefix (filePath , filepath . Clean ( path ) + string (os .PathSeparator )) {
323+ if filePath != file .Name && ! strings .HasPrefix (filePath , cleanPath + string (os .PathSeparator )) {
322324 return fmt .Errorf ("invalid file path %s" , filePath )
323325 }
324326
@@ -334,6 +336,7 @@ func DownloadStarterProjectAsDir(path string, registryURL string, stack string,
334336 }
335337
336338 // open destination file
339+ /* #nosec G304 -- filePath is produced using path.Join which cleans the dir path */
337340 dstFile , err := os .OpenFile (filePath , os .O_WRONLY | os .O_CREATE | os .O_TRUNC , file .Mode ())
338341 if err != nil {
339342 return fmt .Errorf ("error opening destination file at %s: %v" , filePath , err )
@@ -346,12 +349,19 @@ func DownloadStarterProjectAsDir(path string, registryURL string, stack string,
346349 }
347350
348351 // extract source file to destination file
352+ /* #nosec G110 -- starter projects are vetted before they are added to a registry. Their contents can be seen before they are downloaded */
349353 if _ , err = io .Copy (dstFile , srcFile ); err != nil {
350354 return fmt .Errorf ("error extracting file %s from archive %s to destination at %s: %v" , file .Name , archivePath , filePath , err )
351355 }
352356
353- dstFile .Close ()
354- srcFile .Close ()
357+ err = dstFile .Close ()
358+ if err != nil {
359+ return err
360+ }
361+ err = srcFile .Close ()
362+ if err != nil {
363+ return err
364+ }
355365 }
356366
357367 return nil
@@ -360,37 +370,45 @@ func DownloadStarterProjectAsDir(path string, registryURL string, stack string,
360370// DownloadStarterProject downloads a specified starter project archive to a given path
361371func DownloadStarterProject (path string , registryURL string , stack string , starterProject string , options RegistryOptions ) error {
362372 var fileStream * os.File
373+ var returnedErr error
363374
375+ cleanPath := filepath .Clean (path )
364376 // Download Starter Project archive bytes
365377 bytes , err := DownloadStarterProjectAsBytes (registryURL , stack , starterProject , options )
366378 if err != nil {
367379 return err
368380 }
369381
370382 // Error if parent directory does not exist
371- if _ , err = os .Stat (filepath .Dir (path )); os .IsNotExist (err ) {
383+ if _ , err = os .Stat (filepath .Dir (cleanPath )); os .IsNotExist (err ) {
372384 return fmt .Errorf ("parent directory '%s' does not exist: %v" , filepath .Dir (path ), err )
373385 }
374386
375387 // If file does not exist, create a new one
376388 // Else open existing for overwriting
377389 if _ , err = os .Stat (path ); os .IsNotExist (err ) {
378- fileStream , err = os .Create (path )
390+ fileStream , err = os .Create (cleanPath )
379391 if err != nil {
380392 return fmt .Errorf ("failed to create file '%s': %v" , path , err )
381393 }
382394 } else {
383- fileStream , err = os .OpenFile (path , os .O_WRONLY | os .O_TRUNC , os .ModePerm )
395+ fileStream , err = os .OpenFile (cleanPath , os .O_WRONLY | os .O_TRUNC , os .ModePerm )
384396 if err != nil {
385397 return fmt .Errorf ("failed to open file '%s': %v" , path , err )
386398 }
387399 }
388- defer fileStream .Close ()
400+
401+ defer func () {
402+ if err = fileStream .Close (); err != nil {
403+ returnedErr = multierror .Append (returnedErr , err )
404+ }
405+ }()
389406
390407 // Write downloaded bytes to file
391408 _ , err = fileStream .Write (bytes )
392409 if err != nil {
393- return fmt .Errorf ("failed writing to '%s': %v" , path , err )
410+ returnedErr = multierror .Append (returnedErr , fmt .Errorf ("failed writing to '%s': %v" , path , err ))
411+ return returnedErr
394412 }
395413
396414 return nil
0 commit comments