Exposing shell over API is reminiscence of CGI and old college days

Submitted by ravisagar on Tue, 04/03/2018 - 22:40
Ravi in college
Ravi in college

This morning I was going to Reading when I thought of exposing the shell script that I wrote yesterday to read the CSV file where I am storing my GPS location and sending it to my website. I though of this idea where I can simply query my database of flat files. I thought of creating a bash script where I can pass the date and time argument and it will return my GPS coordinates of that day by looking in the CSV files. I also thought of exposing this script using API.

So when I was searching on the net for some libraries I am actually found one called goexpose that might do the job but I was interested in doing something very simple and quick. I also found one link where I found this code.

  1. // This tool exposes any binary (shell command/script) as an HTTP service.
  2. // A remote client can trigger the execution of the command by sending
  3. // a simple HTTP request. The output of the command execution is sent
  4. // back to the client in plain text format.
  5. package main
  6.  
  7. import (
  8.  "flag"
  9.  "fmt"
  10.  "io/ioutil"
  11.  "log"
  12.  "net/http"
  13.  "os"
  14.  "os/exec"
  15.  "strings"
  16. )
  17.  
  18. func main() {
  19.  binary := flag.String("b", "", "Path to the executable binary")
  20.  port := flag.Int("p", 8080, "HTTP port to listen on")
  21.  flag.Parse()
  22.  
  23.  if *binary == "" {
  24.   fmt.Println("Path to binary not specified.")
  25.   return
  26.  }
  27.  
  28.  l := log.New(os.Stdout, "", log.Ldate|log.Ltime)
  29.  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  30.   var argString string
  31.   if r.Body != nil {
  32.    data, err := ioutil.ReadAll(r.Body)
  33.    if err != nil {
  34.     l.Print(err)
  35.     http.Error(w, err.Error(), http.StatusInternalServerError)
  36.     return
  37.    }
  38.    argString = string(data)
  39.   }
  40.  
  41.   fields := strings.Fields(*binary)
  42.   args := append(fields[1:], strings.Fields(argString)...)
  43.   l.Printf("Command: [%s %s]", fields[0], strings.Join(args, " "))
  44.  
  45.   output, err := exec.Command(fields[0], args...).Output()
  46.   if err != nil {
  47.    http.Error(w, err.Error(), http.StatusInternalServerError)
  48.    return
  49.   }
  50.   w.Header().Set("Content-Type", "text/plain")
  51.   w.Write(output)
  52.  })
  53.  
  54.  l.Printf("Listening on port %d...", *port)
  55.  l.Printf("Exposed binary: %s", *binary)
  56.  http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", *port), nil)
  57. }

The code above actually works perfectly. To expose the "date" command as a web API. You can simply run the tool as follows:

./bash2http -b date

Check the link for more details.

However I was not entirely convinced with the approach of this code. There is no security and that is why I will spend more time on goexpose code on github to understand how secure it is. It supports SSL which is assuring. Let us see if I can spend some more time this week. I really want to find a solution. Most likely I will try to make the above code slightly secure and reusable. I just don't understand Go that well yet. I wish if we can simply feed our brain with knowledge while we are sleeping.

I also came to know that the approach of exposing shell using API method so that it can be invoked over the internet is exactly what CGI used to do. It reminded me of the days when we used to work on C++ during our college days. Internet was still quite new in late 1990s and create a web page using C++ was so much fun. All the memories of floppy disk filled with hundreds of CPP files that we used to compile with Alt+F9 and then run with Ctrl+F9 by smashing the keys on TVS gold keyboard. So many amazing memories of college.

I made couple of projects with Chinar in college using graphics in C++ and mouse programming and working with interrupts. I wish if I get find the code again. It is a shame there was no Github back then. I am sure I must have the code somewhere in floppy disks but how will I read them?

Pic 1:Me in my college.

Pic 2: This is my class (Check the bag I still have the same bag here with my in London and I take it to work everyday).

Going to work after ages tomorrow. I am actually missing "Mind the gap" voice. Excited!

Want to contact me?

Life begins outside your comfort zone and that is where your courage is developed". Write to me by filling this form. For living I am an Atlassian Consultant who love both Jira and Drupal. I am the author of "Mastering JIRA" and "Mastering JIRA 7" books. I Love both JIRA and Drupal (a bit more). You can Write To Me and I will get back to you as soon as I can. Have a nice day!

Social Links

Subscribe to my mailing list.

Enter your email address: