@@ -378,13 +378,13 @@ func (cs *CommandService) addConfigApplyEndpoint() {
378378 return
379379 }
380380
381- updatedConfigFiles , externalFilesWereUpdated , err := processConfigApplyRequestBody (c , configFiles )
381+ updatedConfigFiles , externalFilesUpdated , err := processConfigApplyRequestBody (c , configFiles )
382382 if err != nil {
383383 c .JSON (http .StatusBadRequest , gin.H {"error" : err .Error ()})
384384 return
385385 }
386386
387- if externalFilesWereUpdated {
387+ if externalFilesUpdated {
388388 cs .instanceFiles [instanceID ] = updatedConfigFiles
389389 } else {
390390 cs .instanceFiles [instanceID ] = configFiles
@@ -443,38 +443,22 @@ func (cs *CommandService) addExternalFileServerEndpoint() {
443443 // This API will serve individual files from the external directory
444444 cs .server .GET ("/api/v1/externalfile/:filename" , func (c * gin.Context ) {
445445 filename := c .Param ("filename" )
446- // Validate that the filename does not contain path separators or ".."
447- if strings .Contains (filename , "/" ) || strings .Contains (filename , "\\ " ) || strings .Contains (filename , ".." ) {
448- c .JSON (http .StatusBadRequest , gin.H {"error" : "Invalid file name" })
449- return
450- }
451- filePath := filepath .Join (cs .externalFileServer , filename )
452- absBase , err := filepath .Abs (cs .externalFileServer )
453- if err != nil {
454- c .JSON (http .StatusInternalServerError , gin.H {"error" : "Internal error" })
455- return
456- }
457- absFile , err := filepath .Abs (filePath )
446+
447+ absFile , err := validateFile (cs .externalFileServer , filename )
458448 if err != nil {
459- c .JSON (http .StatusBadRequest , gin.H {"error" : "Invalid file name" })
460- return
461- }
462- if ! strings .HasPrefix (absFile , absBase ) {
463- c .JSON (http .StatusBadRequest , gin.H {"error" : "Invalid file name" })
464- return
465- }
449+ if errors .Is (err , os .ErrNotExist ) {
450+ c .JSON (http .StatusNotFound , gin.H {"error" : "File not found" })
451+ } else {
452+ c .JSON (http .StatusBadRequest , gin.H {"error" : err .Error ()})
453+ }
466454
467- // Check if the file exists
468- if _ , file_err := os .Stat (absFile ); os .IsNotExist (file_err ) {
469- c .JSON (http .StatusNotFound , gin.H {"error" : "File not found" })
470455 return
471456 }
472-
473457 // Serve the file
474458 c .File (absFile )
475459 })
476460
477- slog .Info ("Serving individual external files from" , "directory " , cs .externalFileServer )
461+ slog .Info ("Serving individual external files from" , "external_file_server " , cs .externalFileServer )
478462}
479463
480464func (cs * CommandService ) findInstanceConfigFiles (instanceID string ) (configFiles []* mpi.File , err error ) {
@@ -537,6 +521,34 @@ func isValidFile(info os.FileInfo, fileFullPath string) bool {
537521 return ! info .IsDir () && ! strings .HasSuffix (fileFullPath , ".DS_Store" )
538522}
539523
524+ func validateFile (externalFileServer , filename string ) (string , error ) {
525+ if strings .Contains (filename , "/" ) || strings .Contains (filename , "\\ " ) || strings .Contains (filename , ".." ) {
526+ return "" , errors .New ("invalid file name" )
527+ }
528+
529+ filePath := filepath .Join (externalFileServer , filename )
530+
531+ absBase , err := filepath .Abs (externalFileServer )
532+ if err != nil {
533+ return "" , fmt .Errorf ("internal error: %w" , err )
534+ }
535+
536+ absFile , err := filepath .Abs (filePath )
537+ if err != nil {
538+ return "" , fmt .Errorf ("invalid file name: %w" , err )
539+ }
540+
541+ if ! strings .HasPrefix (absFile , absBase ) {
542+ return "" , errors .New ("invalid file name" )
543+ }
544+
545+ if _ , fileErr := os .Stat (absFile ); os .IsNotExist (fileErr ) {
546+ return "" , os .ErrNotExist
547+ }
548+
549+ return absFile , nil
550+ }
551+
540552func processConfigApplyRequestBody (c * gin.Context , initialFiles []* mpi.File ) ([]* mpi.File , bool , error ) {
541553 if c .Request .ContentLength == 0 {
542554 return initialFiles , false , nil
@@ -555,14 +567,26 @@ func processConfigApplyRequestBody(c *gin.Context, initialFiles []*mpi.File) ([]
555567 }
556568
557569 var externalFilesWereUpdated bool
570+ updatedFiles := initialFiles
571+
558572 for _ , ed := range body .ExternalDataSources {
559573 if file , ok := filesMap [ed .FilePath ]; ok {
560574 file .ExternalDataSource = & mpi.ExternalDataSource {
561575 Location : ed .Location ,
562576 }
563- externalFilesWereUpdated = true
577+ } else {
578+ newFile := & mpi.File {
579+ FileMeta : & mpi.FileMeta {
580+ Name : ed .FilePath ,
581+ },
582+ ExternalDataSource : & mpi.ExternalDataSource {
583+ Location : ed .Location ,
584+ },
585+ }
586+ updatedFiles = append (updatedFiles , newFile )
564587 }
588+ externalFilesWereUpdated = true
565589 }
566590
567- return initialFiles , externalFilesWereUpdated , nil
591+ return updatedFiles , externalFilesWereUpdated , nil
568592}
0 commit comments