Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Usage of shhttp:
If non-empty, write log files in this directory
-logtostderr
log to standard error instead of files
-password string
HTTP API password
-port int
port to listen on (default 2112)
-stderrthreshold value
Expand Down
3 changes: 2 additions & 1 deletion cmd/shhttp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func main() {
cleanup := flag.Int("clean-interval", -1, "interval (hours) after which finished jobs are cleaned")
location := flag.String("dir", "shhttp", "location to store the job data")
revive := flag.Bool("revive", false, "Whether to revive previous running jobs if there are any")
password := flag.String("password", "", "HTTP API password")

flag.Parse()

Expand All @@ -40,7 +41,7 @@ func main() {
}()
}

router := pkg.GetRouter(jobStore, savedJobStore, *revive)
router := pkg.GetRouter(jobStore, savedJobStore, *revive, *password)
address := strings.Join([]string{*hostname, strconv.Itoa(*port)}, ":")
glog.Infof("starting HTTP listener at %s", address)
glog.Fatal(http.ListenAndServe(address, router))
Expand Down
69 changes: 68 additions & 1 deletion pkg/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (j FileBasedJobStore) DeleteJob(id string) error {
}
}

func GetRouter(jobStore JobStore, savedJobStore JobStore, revive bool) *mux.Router {
func GetRouter(jobStore JobStore, savedJobStore JobStore, revive bool, password string) *mux.Router {
router := mux.NewRouter()

jobQueue := make(chan *Job)
Expand Down Expand Up @@ -312,6 +312,14 @@ func GetRouter(jobStore JobStore, savedJobStore JobStore, revive bool) *mux.Rout
writeErrorResponse(err, http.StatusBadRequest, writer)
return
}
if executable.Password != password {
err := errors.New("password invalid");
glog.Error(err)
writeErrorResponse(err, http.StatusUnauthorized, writer)
return
}
// Omit the "Password" field when marshaling if any.
executable.Password = ""
result := ExecResult{Executable: &executable}
Execute(&result)
respData, err := json.Marshal(result)
Expand All @@ -333,18 +341,47 @@ func GetRouter(jobStore JobStore, savedJobStore JobStore, revive bool) *mux.Rout
writeErrorResponse(err, http.StatusBadRequest, writer)
return
}
if job.Password != password {
err := errors.New("password invalid");
glog.Error(err)
writeErrorResponse(err, http.StatusUnauthorized, writer)
return
}
// Omit the "Password" field when marshaling if any.
job.Password = ""
runJob(writer, request, &job, queue)
})

router.Path("/v1/jobs").Methods(http.MethodGet).HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
q := request.URL.Query()
if q.Get("password") != password {
err := errors.New("password invalid");
glog.Error(err)
writeErrorResponse(err, http.StatusUnauthorized, writer)
return
}
getIds(writer, request, jobStore)
})

router.Path("/v1/jobs/{id}").Methods(http.MethodGet).HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
q := request.URL.Query()
if q.Get("password") != password {
err := errors.New("password invalid");
glog.Error(err)
writeErrorResponse(err, http.StatusUnauthorized, writer)
return
}
getJob(writer, request, jobStore)
})

router.Path("/v1/saved").Methods(http.MethodGet).HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
q := request.URL.Query()
if q.Get("password") != password {
err := errors.New("password invalid");
glog.Error(err)
writeErrorResponse(err, http.StatusUnauthorized, writer)
return
}
getIds(writer, request, savedJobStore)
})

Expand All @@ -357,6 +394,14 @@ func GetRouter(jobStore JobStore, savedJobStore JobStore, revive bool) *mux.Rout
writeErrorResponse(err, http.StatusBadRequest, writer)
return
}
if job.Password != password {
err := errors.New("password invalid");
glog.Error(err)
writeErrorResponse(err, http.StatusUnauthorized, writer)
return
}
// Omit the "Password" field when marshaling if any.
job.Password = ""
if job.Id == "" {
job.Id = uuid.New().String()
}
Expand All @@ -367,6 +412,13 @@ func GetRouter(jobStore JobStore, savedJobStore JobStore, revive bool) *mux.Rout

router.Path("/v1/saved/{id}").Methods(http.MethodDelete).HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writeContentType(writer)
q := request.URL.Query()
if q.Get("password") != password {
err := errors.New("password invalid");
glog.Error(err)
writeErrorResponse(err, http.StatusUnauthorized, writer)
return
}
vars := mux.Vars(request)
id := vars["id"]
err := savedJobStore.DeleteJob(id)
Expand All @@ -378,6 +430,13 @@ func GetRouter(jobStore JobStore, savedJobStore JobStore, revive bool) *mux.Rout
})

router.Path("/v1/saved/{id}").Methods(http.MethodGet).HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
q := request.URL.Query()
if q.Get("password") != password {
err := errors.New("password invalid");
glog.Error(err)
writeErrorResponse(err, http.StatusUnauthorized, writer)
return
}
getJob(writer, request, savedJobStore)
})

Expand All @@ -399,6 +458,14 @@ func GetRouter(jobStore JobStore, savedJobStore JobStore, revive bool) *mux.Rout
if err != nil {
glog.Error(err)
} else {
if runBody.Password != password {
err := errors.New("password invalid");
glog.Error(err)
writeErrorResponse(err, http.StatusUnauthorized, writer)
return
}
// Omit the "Password" field when marshaling if any.
runBody.Password = ""
updateJobEnv(job, runBody.Env)
}
runJob(writer, request, job, queue)
Expand Down
17 changes: 10 additions & 7 deletions pkg/structs.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package pkg

type Executable struct {
Command string
Args []string
BaseDir string
Stdin string
Shell bool
Env map[string]string
Command string
Args []string
BaseDir string
Stdin string
Shell bool
Env map[string]string
Password string `json:"Password,omitempty"`
}

type ExecResult struct {
Expand Down Expand Up @@ -34,10 +35,12 @@ type Job struct {
Created int64
LastModified int64
IgnoreErrors bool
Password string `json:"Password,omitempty"`
}

type RunBody struct {
Env map[string]string
Env map[string]string
Password string `json:"Password,omitempty"`
}

type IdsResponse struct {
Expand Down