From 57f6c33221989cbd461e7dede1c75126962639d5 Mon Sep 17 00:00:00 2001 From: MrStashley Date: Fri, 15 Mar 2024 11:45:36 -0700 Subject: [PATCH 1/3] implemented list dir for config --- src/models/model.ts | 17 ++++++++++++++ wavesrv/cmd/main-server.go | 48 +++++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/models/model.ts b/src/models/model.ts index 04d7a29f6..20733e89b 100644 --- a/src/models/model.ts +++ b/src/models/model.ts @@ -216,6 +216,23 @@ class Model { return resp.json(); }).then((userKeybindings) => { this.keybindManager.setUserKeybindings(userKeybindings); + this.testConfigListDir(); + }); + } + + testConfigListDir() { + const url = new URL(this.getBaseHostPort() + "/config/"); + let prtn = fetch(url, { method: "get", body: null, headers: this.getFetchHeaders() }); + prtn.then((resp) => { + if (resp.status == 404) { + return []; + } else if (!resp.ok) { + console.log("resp not ok", resp); + util.handleNotOkResp(resp, url); + } + return resp.json(); + }).then((configDirList) => { + console.log("got json: ", configDirList); }); } diff --git a/wavesrv/cmd/main-server.go b/wavesrv/cmd/main-server.go index f106ac4d4..b0bbff6b0 100644 --- a/wavesrv/cmd/main-server.go +++ b/wavesrv/cmd/main-server.go @@ -677,6 +677,24 @@ func HandleRunCommand(w http.ResponseWriter, r *http.Request) { WriteJsonSuccess(w, update) } +func CheckIsDir(dirHandler http.Handler, fileHandler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + configPath := r.URL.Path + configFullPath := path.Join(scbase.GetWaveHomeDir(), configPath) + fstat, err := os.Stat(configFullPath) + if err != nil { + w.WriteHeader(500) + w.Write([]byte(fmt.Sprintf("file stat err", err))) + return + } + if fstat.IsDir() { + AuthKeyMiddleWare(dirHandler).ServeHTTP(w, r) + } else { + AuthKeyMiddleWare(fileHandler).ServeHTTP(w, r) + } + }) +} + func AuthKeyMiddleWare(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { reqAuthKey := r.Header.Get("X-AuthKey") @@ -857,6 +875,32 @@ func doShutdown(reason string) { }) } +func configDirHandler(w http.ResponseWriter, r *http.Request) { + configPath := r.URL.Path + configFullPath := path.Join(scbase.GetWaveHomeDir(), configPath) + dirFile, err := os.Open(configFullPath) + if err != nil { + w.WriteHeader(500) + w.Write([]byte(fmt.Sprintf("error opening specified dir: ", err))) + return + } + entries, err := dirFile.Readdirnames(0) + if err != nil { + w.WriteHeader(500) + w.Write([]byte(fmt.Sprintf("error getting files: ", err))) + return + } + dirListJson, err := json.Marshal(entries) + if err != nil { + w.WriteHeader(500) + w.Write([]byte(fmt.Sprintf("json err: ", err))) + return + } + w.WriteHeader(200) + w.Header().Set("Content-Type", "application/json") + w.Write(dirListJson) +} + func main() { scbase.BuildTime = BuildTime scbase.WaveVersion = WaveVersion @@ -953,7 +997,9 @@ func main() { gr.HandleFunc("/api/write-file", AuthKeyWrap(HandleWriteFile)).Methods("POST") configPath := path.Join(scbase.GetWaveHomeDir(), "config") + "/" log.Printf("[wave] config path: %q\n", configPath) - gr.PathPrefix("/config/").Handler(AuthKeyMiddleWare(http.StripPrefix("/config/", http.FileServer(http.Dir(configPath))))) + isFileHandler := http.StripPrefix("/config/", http.FileServer(http.Dir(configPath))) + isDirHandler := http.HandlerFunc(configDirHandler) + gr.PathPrefix("/config/").Handler(CheckIsDir(isDirHandler, isFileHandler)) serverAddr := MainServerAddr if scbase.IsDevMode() { From ca0240c4030890ec7d4c96e9b24088a490fc5217 Mon Sep 17 00:00:00 2001 From: MrStashley Date: Mon, 18 Mar 2024 15:16:53 -0700 Subject: [PATCH 2/3] added file stat and path check --- src/models/model.ts | 17 ------------ src/types/custom.d.ts | 4 +++ waveshell/pkg/packet/packet.go | 49 ++++++++++++++++++++++++++++++++++ wavesrv/cmd/main-server.go | 26 +++++++++++++++--- 4 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/models/model.ts b/src/models/model.ts index 20733e89b..04d7a29f6 100644 --- a/src/models/model.ts +++ b/src/models/model.ts @@ -216,23 +216,6 @@ class Model { return resp.json(); }).then((userKeybindings) => { this.keybindManager.setUserKeybindings(userKeybindings); - this.testConfigListDir(); - }); - } - - testConfigListDir() { - const url = new URL(this.getBaseHostPort() + "/config/"); - let prtn = fetch(url, { method: "get", body: null, headers: this.getFetchHeaders() }); - prtn.then((resp) => { - if (resp.status == 404) { - return []; - } else if (!resp.ok) { - console.log("resp not ok", resp); - util.handleNotOkResp(resp, url); - } - return resp.json(); - }).then((configDirList) => { - console.log("got json: ", configDirList); }); } diff --git a/src/types/custom.d.ts b/src/types/custom.d.ts index 9d3383af9..466a930bd 100644 --- a/src/types/custom.d.ts +++ b/src/types/custom.d.ts @@ -797,12 +797,16 @@ declare global { }; type FileInfoType = { + type: string; name: string; size: number; modts: number; isdir: boolean; perm: number; notfound: boolean; + modestr?: string; + path?: string; + outputpos?: number; }; type ExtBlob = Blob & { diff --git a/waveshell/pkg/packet/packet.go b/waveshell/pkg/packet/packet.go index ff89de4d4..6419a1d1e 100644 --- a/waveshell/pkg/packet/packet.go +++ b/waveshell/pkg/packet/packet.go @@ -11,9 +11,11 @@ import ( "errors" "fmt" "io" + "io/fs" "os" "reflect" "sync" + "time" "github.com/wavetermdev/waveterm/waveshell/pkg/base" "github.com/wavetermdev/waveterm/waveshell/pkg/wlog" @@ -58,6 +60,7 @@ const ( WriteFileReadyPacketStr = "writefileready" // rpc-response WriteFileDonePacketStr = "writefiledone" // rpc-response FileDataPacketStr = "filedata" + FileStatPacketStr = "filestat" LogPacketStr = "log" // logging packet (sent from waveshell back to server) ShellStatePacketStr = "shellstate" @@ -112,6 +115,7 @@ func init() { TypeStrToFactory[WriteFileDonePacketStr] = reflect.TypeOf(WriteFileDonePacketType{}) TypeStrToFactory[LogPacketStr] = reflect.TypeOf(LogPacketType{}) TypeStrToFactory[ShellStatePacketStr] = reflect.TypeOf(ShellStatePacketType{}) + TypeStrToFactory[FileStatPacketStr] = reflect.TypeOf(FileStatPacketType{}) var _ RpcPacketType = (*RunPacketType)(nil) var _ RpcPacketType = (*GetCmdPacketType)(nil) @@ -379,6 +383,51 @@ func MakeReInitPacket() *ReInitPacketType { return &ReInitPacketType{Type: ReInitPacketStr} } +type FileStatPacketType struct { + Type string `json:"type"` + Name string `json:"name"` + Size int64 `json:"size"` + ModTs time.Time `json:"modts"` + IsDir bool `json:"isdir"` + Perm int `json:"perm"` + ModeStr string `json:"modestr"` + Error string `json:"error"` + Done bool `json:"done"` + RespId string `json:"respid"` + Path string `json:"path"` +} + +func (*FileStatPacketType) GetType() string { + return FileStatPacketStr +} + +func (p *FileStatPacketType) GetResponseDone() bool { + return p.Done +} + +func (p *FileStatPacketType) GetResponseId() string { + return p.RespId +} + +func MakeFileStatPacketType() *FileStatPacketType { + return &FileStatPacketType{Type: FileStatPacketStr} +} + +func MakeFileStatPacketFromFileInfo(finfo fs.FileInfo, err string, done bool) *FileStatPacketType { + resp := MakeFileStatPacketType() + resp.Error = err + resp.Done = done + + resp.IsDir = finfo.IsDir() + resp.Name = finfo.Name() + + resp.Size = finfo.Size() + resp.ModTs = finfo.ModTime() + resp.Perm = int(finfo.Mode().Perm()) + resp.ModeStr = finfo.Mode().String() + return resp +} + type StreamFilePacketType struct { Type string `json:"type"` ReqId string `json:"reqid"` diff --git a/wavesrv/cmd/main-server.go b/wavesrv/cmd/main-server.go index b0bbff6b0..faa7f0987 100644 --- a/wavesrv/cmd/main-server.go +++ b/wavesrv/cmd/main-server.go @@ -680,7 +680,20 @@ func HandleRunCommand(w http.ResponseWriter, r *http.Request) { func CheckIsDir(dirHandler http.Handler, fileHandler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { configPath := r.URL.Path - configFullPath := path.Join(scbase.GetWaveHomeDir(), configPath) + configAbsPath, err := filepath.Abs(configPath) + if err != nil { + w.WriteHeader(500) + w.Write([]byte(fmt.Sprintf("error getting absolute path", err))) + return + } + configBaseDir := path.Join(scbase.GetWaveHomeDir(), "config") + configFullPath := path.Join(scbase.GetWaveHomeDir(), configAbsPath) + log.Printf("base dir: %v full path: %v", configBaseDir, configFullPath) + if !strings.HasPrefix(configFullPath, configBaseDir) { + w.WriteHeader(500) + w.Write([]byte(fmt.Sprintf("error: path is not in config folder"))) + return + } fstat, err := os.Stat(configFullPath) if err != nil { w.WriteHeader(500) @@ -876,6 +889,7 @@ func doShutdown(reason string) { } func configDirHandler(w http.ResponseWriter, r *http.Request) { + log.Printf("running?") configPath := r.URL.Path configFullPath := path.Join(scbase.GetWaveHomeDir(), configPath) dirFile, err := os.Open(configFullPath) @@ -884,13 +898,19 @@ func configDirHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte(fmt.Sprintf("error opening specified dir: ", err))) return } - entries, err := dirFile.Readdirnames(0) + entries, err := dirFile.Readdir(0) if err != nil { w.WriteHeader(500) w.Write([]byte(fmt.Sprintf("error getting files: ", err))) return } - dirListJson, err := json.Marshal(entries) + var files []*packet.FileStatPacketType + for index := 0; index < len(entries); index++ { + curEntry := entries[index] + curFile := packet.MakeFileStatPacketFromFileInfo(curEntry, "", false) + files = append(files, curFile) + } + dirListJson, err := json.Marshal(files) if err != nil { w.WriteHeader(500) w.Write([]byte(fmt.Sprintf("json err: ", err))) From 2c572dd9d58cdcc66a36adadce374f62b4c21fc2 Mon Sep 17 00:00:00 2001 From: MrStashley Date: Mon, 18 Mar 2024 16:50:18 -0700 Subject: [PATCH 3/3] addressed comments, added file not found error --- wavesrv/cmd/main-server.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wavesrv/cmd/main-server.go b/wavesrv/cmd/main-server.go index faa7f0987..3e8b7f196 100644 --- a/wavesrv/cmd/main-server.go +++ b/wavesrv/cmd/main-server.go @@ -688,14 +688,17 @@ func CheckIsDir(dirHandler http.Handler, fileHandler http.Handler) http.Handler } configBaseDir := path.Join(scbase.GetWaveHomeDir(), "config") configFullPath := path.Join(scbase.GetWaveHomeDir(), configAbsPath) - log.Printf("base dir: %v full path: %v", configBaseDir, configFullPath) if !strings.HasPrefix(configFullPath, configBaseDir) { w.WriteHeader(500) w.Write([]byte(fmt.Sprintf("error: path is not in config folder"))) return } fstat, err := os.Stat(configFullPath) - if err != nil { + if errors.Is(err, fs.ErrNotExist) { + w.WriteHeader(404) + w.Write([]byte(fmt.Sprintf("file not found: ", configAbsPath))) + return + } else if err != nil { w.WriteHeader(500) w.Write([]byte(fmt.Sprintf("file stat err", err))) return