From 4816338128734032e3d321a1966e8be3c914548d Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Fri, 4 Jan 2019 22:00:07 +0000 Subject: [PATCH] feat: operational backend License: MIT Signed-off-by: Henrique Dias --- http/{websockets.go => commands.go} | 97 ++++++++++------------------- http/http.go | 19 +----- http/search.go | 28 +++++++++ search/search.go | 9 ++- 4 files changed, 68 insertions(+), 85 deletions(-) rename http/{websockets.go => commands.go} (50%) create mode 100644 http/search.go diff --git a/http/websockets.go b/http/commands.go similarity index 50% rename from http/websockets.go rename to http/commands.go index 28a3bbac..4e9add25 100644 --- a/http/websockets.go +++ b/http/commands.go @@ -1,6 +1,18 @@ package http -/* +import ( + "bufio" + "io" + "log" + "net/http" + "os/exec" + "strings" + "time" + + "github.com/filebrowser/filebrowser/runner" + "github.com/gorilla/websocket" +) + var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, @@ -10,16 +22,18 @@ var ( cmdNotAllowed = []byte("Command not allowed.") ) -func (e *env) commandsHandler(w http.ResponseWriter, r *http.Request) { - user, ok := e.getUser(w, r) - if !ok { - return +func wsErr(ws *websocket.Conn, r *http.Request, status int, err error) { + txt := http.StatusText(status) + if err != nil || status >= 400 { + log.Printf("%s: %v %s %v", r.URL.Path, status, r.RemoteAddr, err) } + ws.WriteControl(websocket.CloseInternalServerErr, []byte(txt), time.Now().Add(10*time.Second)) +} +var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { - httpErr(w, r, http.StatusInternalServerError, err) - return + return http.StatusInternalServerError, err } defer conn.Close() @@ -29,7 +43,7 @@ func (e *env) commandsHandler(w http.ResponseWriter, r *http.Request) { _, msg, err := conn.ReadMessage() if err != nil { wsErr(conn, r, http.StatusInternalServerError, err) - return + return 0, nil } raw = strings.TrimSpace(string(msg)) @@ -38,45 +52,43 @@ func (e *env) commandsHandler(w http.ResponseWriter, r *http.Request) { } } - if !user.CanExecute(strings.Split(raw, " ")[0]) { + if !d.user.CanExecute(strings.Split(raw, " ")[0]) { err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed) if err != nil { wsErr(conn, r, http.StatusInternalServerError, err) } - return + return 0, nil } - command, err := e.ParseCommand(raw) + command, err := runner.ParseCommand(d.settings, raw) if err != nil { err := conn.WriteMessage(websocket.TextMessage, []byte(err.Error())) if err != nil { wsErr(conn, r, http.StatusInternalServerError, err) } - return + return 0, nil } - path := strings.TrimPrefix(r.URL.Path, "/api/command") - dir := user.FullPath(path) cmd := exec.Command(command[0], command[1:]...) - cmd.Dir = dir + cmd.Dir = d.user.FullPath(r.URL.Path) stdout, err := cmd.StdoutPipe() if err != nil { wsErr(conn, r, http.StatusInternalServerError, err) - return + return 0, nil } stderr, err := cmd.StderrPipe() if err != nil { wsErr(conn, r, http.StatusInternalServerError, err) - return + return 0, nil } if err := cmd.Start(); err != nil { wsErr(conn, r, http.StatusInternalServerError, err) - return + return 0, nil } s := bufio.NewScanner(io.MultiReader(stdout, stderr)) @@ -87,51 +99,6 @@ func (e *env) commandsHandler(w http.ResponseWriter, r *http.Request) { if err := cmd.Wait(); err != nil { wsErr(conn, r, http.StatusInternalServerError, err) } -} -func (e *env) searchHandler(w http.ResponseWriter, r *http.Request) { - user, ok := e.getUser(w, r) - if !ok { - return - } - - conn, err := upgrader.Upgrade(w, r, nil) - if err != nil { - httpErr(w, r, http.StatusInternalServerError, err) - return - } - defer conn.Close() - - var ( - value string - message []byte - ) - - for { - _, message, err = conn.ReadMessage() - if err != nil { - httpErr(w, r, http.StatusInternalServerError, err) - return - } - - if len(message) != 0 { - value = string(message) - break - } - } - - scope := strings.TrimPrefix(r.URL.Path, "/api/search") - err = search.Search(user.Fs, scope, value, func(path string, f os.FileInfo) error { - response, _ := json.Marshal(map[string]interface{}{ - "dir": f.IsDir(), - "path": path, - }) - - return conn.WriteMessage(websocket.TextMessage, response) - }) - - if err != nil { - httpErr(w, r, http.StatusInternalServerError, err) - return - } -} */ + return 0, nil +}) diff --git a/http/http.go b/http/http.go index 96c85ae0..cbdf079d 100644 --- a/http/http.go +++ b/http/http.go @@ -47,25 +47,10 @@ func NewHandler(storage *storage.Storage) (http.Handler, error) { api.Handle("/settings", handle(settingsPutHandler, "", storage)).Methods("PUT") api.PathPrefix("/raw").Handler(handle(rawHandler, "/api/raw", storage)).Methods("GET") - /* api.PathPrefix("/command").HandlerFunc(e.auth(e.commandsHandler)) - api.PathPrefix("/search").HandlerFunc(e.auth(e.searchHandler)) */ + api.PathPrefix("/command").Handler(handle(commandsHandler, "/api/command", storage)).Methods("GET") + api.PathPrefix("/search").Handler(handle(searchHandler, "/api/search", storage)).Methods("GET") return r, nil } -/* -type key int - - - - - -func wsErr(ws *websocket.Conn, r *http.Request, status int, err error) { - txt := http.StatusText(status) - if err != nil || status >= 400 { - log.Printf("%s: %v %s %v", r.URL.Path, status, r.RemoteAddr, err) - } - ws.WriteControl(websocket.CloseInternalServerErr, []byte(txt), time.Now().Add(10*time.Second)) -} -*/ diff --git a/http/search.go b/http/search.go new file mode 100644 index 00000000..58d9ddd8 --- /dev/null +++ b/http/search.go @@ -0,0 +1,28 @@ +package http + +import ( + "net/http" + "os" + + "github.com/filebrowser/filebrowser/search" +) + +var searchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { + response := []map[string]interface{}{} + query := r.URL.Query().Get("query") + + err := search.Search(d.user.Fs, r.URL.Path, query, d, func(path string, f os.FileInfo) error { + response = append(response, map[string]interface{}{ + "dir": f.IsDir(), + "path": path, + }) + + return nil + }) + + if err != nil { + return http.StatusInternalServerError, err + } + + return renderJSON(w, r, response) +}) diff --git a/search/search.go b/search/search.go index a035fddc..a558176a 100644 --- a/search/search.go +++ b/search/search.go @@ -4,6 +4,7 @@ import ( "os" "strings" + "github.com/filebrowser/filebrowser/rules" "github.com/spf13/afero" ) @@ -13,13 +14,15 @@ type searchOptions struct { Terms []string } -// TODO: move to FIle Browser and also check for IsAllowed - // Search searches for a query in a fs. -func Search(fs afero.Fs, scope string, query string, found func(path string, f os.FileInfo) error) error { +func Search(fs afero.Fs, scope, query string, checker rules.Checker, found func(path string, f os.FileInfo) error) error { search := parseSearch(query) return afero.Walk(fs, scope, func(path string, f os.FileInfo, err error) error { + if !checker.Check(path) { + return nil + } + path = strings.TrimPrefix(path, "/") path = strings.Replace(path, "\\", "/", -1)