diff --git a/filebrowser.json b/filebrowser.json new file mode 100644 index 00000000..2a791292 --- /dev/null +++ b/filebrowser.json @@ -0,0 +1,71 @@ +{ + "settings": { + "key": "P9K5v4kaFKonVZ1IeeiO5MPSk4xKjK/lN5ZICsVycOX0p1u7ZK4wTpQt7djkCwcx0eLdbMzUixJrkYbAFEoTUQ==", + "signup": false, + "createUserDir": false, + "userHomeBasePath": "/users", + "defaults": { + "scope": ".", + "locale": "en", + "viewMode": "mosaic", + "singleClick": false, + "sorting": { + "by": "", + "asc": false + }, + "perm": { + "admin": false, + "execute": true, + "create": true, + "rename": true, + "modify": true, + "delete": true, + "share": true, + "download": true + }, + "commands": ["grep", "ls", "bash"], + "hideDotfiles": false, + "dateFormat": false + }, + "authMethod": "json", + "branding": { + "name": "", + "disableExternal": false, + "files": "", + "theme": "", + "color": "" + }, + "commands": { + "after_copy": [], + "after_delete": [], + "after_rename": [], + "after_save": [], + "after_upload": [], + "before_copy": [], + "before_delete": [], + "before_rename": [], + "before_save": [], + "before_upload": [] + }, + "shell": [], + "rules": [] + }, + "server": { + "root": ".", + "baseURL": "", + "socket": "", + "tlsKey": "", + "tlsCert": "", + "port": "8080", + "address": "127.0.0.1", + "log": "stdout", + "enableThumbnails": false, + "resizePreview": false, + "enableExec": false, + "typeDetectionByHeader": false, + "authHook": "" + }, + "auther": { + "recaptcha": null + } +} diff --git a/frontend/src/api/commands.js b/frontend/src/api/commands.js index 790c22a7..b5bf8f36 100644 --- a/frontend/src/api/commands.js +++ b/frontend/src/api/commands.js @@ -7,6 +7,7 @@ const protocol = ssl ? "wss:" : "ws:"; export default function command(url, command, onmessage, onclose) { url = removePrefix(url); + console.log(command) url = `${protocol}//${window.location.host}${baseURL}/api/command${url}?auth=${store.state.jwt}`; let conn = new window.WebSocket(url); diff --git a/http/commands.go b/http/commands.go index 022079dd..d513240d 100644 --- a/http/commands.go +++ b/http/commands.go @@ -2,6 +2,7 @@ package http import ( "bufio" + "fmt" "io" "log" "net/http" @@ -59,9 +60,12 @@ var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *d } } - command, err := runner.ParseCommand(d.settings, raw) + command, err := runner.ParseCommand(d.settings, raw, r.URL.Path) + + // fmt.Println("Full Command: ", command) if err != nil { if err := conn.WriteMessage(websocket.TextMessage, []byte(err.Error())); err != nil { //nolint:govet + wsErr(conn, r, http.StatusInternalServerError, err) } return 0, nil @@ -76,21 +80,25 @@ var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *d } cmd := exec.Command(command[0], command[1:]...) //nolint:gosec + // needs glob expansion somehow cmd.Dir = d.user.FullPath(r.URL.Path) stdout, err := cmd.StdoutPipe() if err != nil { + fmt.Println("or here") wsErr(conn, r, http.StatusInternalServerError, err) return 0, nil } stderr, err := cmd.StderrPipe() if err != nil { + fmt.Println("failed here") wsErr(conn, r, http.StatusInternalServerError, err) return 0, nil } if err := cmd.Start(); err != nil { + fmt.Println("or there") wsErr(conn, r, http.StatusInternalServerError, err) return 0, nil } diff --git a/runner/parser.go b/runner/parser.go index 65891f5f..e9e94063 100644 --- a/runner/parser.go +++ b/runner/parser.go @@ -1,15 +1,65 @@ package runner import ( + "fmt" "os/exec" + "path/filepath" + "strings" "github.com/filebrowser/filebrowser/v2/settings" ) +func GlobExpand(args []string, cwd string) ([]string, error) { + var expandedArgs []string + + for _, arg := range args { + + //Sets the path from the current working directory to the argument supplied. + arg_path := "." + cwd + arg + //Expands the globs in the filesystem. + matches, err := filepath.Glob(arg_path) + + if err != nil { + return nil, err + } + //No match means the argument is just appended to the end. + if len(matches) == 0 { + expandedArgs = append(expandedArgs, arg) + } else { + for _, match := range matches { + if err != nil { + return nil, err + } + + //now we need to remove what was appended by cwd + if err != nil { + return nil, err + } + + // The match path is longer than the cwd path + splitCwdLength := len(strings.Split(cwd, "/")) - 2 //Split includes the whitspaces here, so the expected length is two less. + matchSplitLength := len(strings.Split(match, "/")) + + //if the split diff is more than one, then add an extra number to help with slicing the array. + //If this step does not exist, then an empty string will be returned on join, if dir depth is 1 + if matchSplitLength-splitCwdLength > 1 { + splitCwdLength++ + } + newMatch := strings.Join(strings.Split(match, "/")[splitCwdLength:], "/") + //Add to the end of the args + expandedArgs = append(expandedArgs, newMatch) + } + } + } + + return expandedArgs, nil + +} + // ParseCommand parses the command taking in account if the current // instance uses a shell to run the commands or just calls the binary -// directyly. -func ParseCommand(s *settings.Settings, raw string) ([]string, error) { +// directly. +func ParseCommand(s *settings.Settings, raw string, cwd string) ([]string, error) { var command []string if len(s.Shell) == 0 { @@ -18,6 +68,13 @@ func ParseCommand(s *settings.Settings, raw string) ([]string, error) { return nil, err } + // TODO General regex file expansions for commands like ls as well. + args, err = GlobExpand(args, cwd) + + if err != nil { + return nil, err + } + _, err = exec.LookPath(cmd) if err != nil { return nil, err @@ -29,5 +86,7 @@ func ParseCommand(s *settings.Settings, raw string) ([]string, error) { command = append(s.Shell, raw) //nolint:gocritic } + fmt.Println("Final Command: ", command) + return command, nil } diff --git a/runner/runner.go b/runner/runner.go index 2dbafa5c..746b37f7 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -60,7 +60,7 @@ func (r *Runner) exec(raw, evt, path, dst string, user *users.User) error { raw = strings.TrimSpace(strings.TrimSuffix(raw, "&")) } - command, err := ParseCommand(r.Settings, raw) + command, err := ParseCommand(r.Settings, raw, path) if err != nil { return err }