From 3fe884670d6936ec64fd11c8a1fe77e8877c8423 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 17 May 2020 15:07:11 -0700 Subject: [PATCH] Fix handling of files with special characters and spaces closes pterodactyl/panel#2040 closes pterodactyl/panel#2038 --- router/router_server_files.go | 35 +++++++++++++++++++++++++++++------ server/filesystem.go | 13 ++++++------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/router/router_server_files.go b/router/router_server_files.go index 7678e89..f0b28e6 100644 --- a/router/router_server_files.go +++ b/router/router_server_files.go @@ -4,14 +4,24 @@ import ( "bufio" "github.com/gin-gonic/gin" "net/http" + "net/url" "os" "strconv" + "strings" ) // Returns the contents of a file on the server. func getServerFileContents(c *gin.Context) { s := GetServer(c.Param("server")) - cleaned, err := s.Filesystem.SafePath(c.Query("file")) + + p, err := url.QueryUnescape(c.Query("file")) + if err != nil { + TrackedServerError(err, s).AbortWithServerError(c) + return + } + p = "/" + strings.TrimLeft(p, "/") + + cleaned, err := s.Filesystem.SafePath(p) if err != nil { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{ "error": "The file requested could not be found.", @@ -56,7 +66,13 @@ func getServerFileContents(c *gin.Context) { func getServerListDirectory(c *gin.Context) { s := GetServer(c.Param("server")) - stats, err := s.Filesystem.ListDirectory(c.Query("directory")) + d, err := url.QueryUnescape(c.Query("directory")) + if err != nil { + TrackedServerError(err, s).AbortWithServerError(c) + return + } + + stats, err := s.Filesystem.ListDirectory(d) if err != nil { TrackedServerError(err, s).AbortWithServerError(c) return @@ -69,9 +85,9 @@ func getServerListDirectory(c *gin.Context) { func putServerRenameFile(c *gin.Context) { s := GetServer(c.Param("server")) - var data struct{ + var data struct { RenameFrom string `json:"rename_from"` - RenameTo string `json:"rename_to"` + RenameTo string `json:"rename_to"` } c.BindJSON(&data) @@ -128,7 +144,14 @@ func postServerDeleteFile(c *gin.Context) { func postServerWriteFile(c *gin.Context) { s := GetServer(c.Param("server")) - if err := s.Filesystem.Writefile(c.Query("file"), c.Request.Body); err != nil { + f, err := url.QueryUnescape(c.Query("file")) + if err != nil { + TrackedServerError(err, s).AbortWithServerError(c) + return + } + f = "/" + strings.TrimLeft(f, "/") + + if err := s.Filesystem.Writefile(f, c.Request.Body); err != nil { TrackedServerError(err, s).AbortWithServerError(c) return } @@ -152,4 +175,4 @@ func postServerCreateDirectory(c *gin.Context) { } c.Status(http.StatusNoContent) -} \ No newline at end of file +} diff --git a/server/filesystem.go b/server/filesystem.go index 3f2d1f7..a587a12 100644 --- a/server/filesystem.go +++ b/server/filesystem.go @@ -401,13 +401,12 @@ func (fs *Filesystem) Copy(p string) error { return errors.WithStack(err) } - if s, err := os.Stat(cleaned); (err != nil && os.IsNotExist(err)) || s.IsDir() || !s.Mode().IsRegular() { - // For now I think I am okay just returning a nil response if the thing - // we're trying to copy doesn't exist. Probably will want to come back and - // re-evaluate if this is a smart decision (I'm guessing not). - return nil - } else if err != nil { - return errors.WithStack(err) + if s, err := os.Stat(cleaned); err != nil { + return err + } else if s.IsDir() || !s.Mode().IsRegular() { + // If this is a directory or not a regular file, just throw a not-exist error + // since anything calling this function should understand what that means. + return os.ErrNotExist } base := filepath.Base(cleaned)