func (app *App) restrictAdmin(h http.Handler) http.Handler { hf := func(w http.ResponseWriter, r *http.Request) { if user, ok := app.getUser(r); ok { tx, err := app.db.Begin() if err != nil { app.dbError(w, r, err) return } u, err := db.GetUser(tx, user.Name) tx.Rollback() if err != nil { app.dbError(w, r, err) return } if u.Admin { h.ServeHTTP(w, r) return } } if r.Method == "GET" { http.Redirect(w, r, "/", http.StatusTemporaryRedirect) } else { http.Error(w, "Unauthorized", http.StatusUnauthorized) } } return http.HandlerFunc(hf) }
func (app *App) handleUserByName(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": vars := mux.Vars(r) username := vars["name"] // only return all user data if the session user has // admin privlages. Need to check the session user against // the User table. u, ok := app.getUser(r) if !ok || (u.Name != username) { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } tx, err := app.db.Begin() if err != nil { app.dbError(w, r, err) return } defer tx.Rollback() user, err := db.GetUser(tx, username) if err != nil { if db.IsNotFound(err) { http.Error(w, "User not found", http.StatusNotFound) } else { app.dbError(w, r, err) } return } app.writeJson(w, user) default: http.Error(w, "I only respond to GETs", http.StatusNotImplemented) } }
func (app *App) handleUser(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { http.Error(w, "I only respond to GETs", http.StatusNotImplemented) return } u, ok := app.getUser(r) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } tx, err := app.db.Begin() if err != nil { app.dbError(w, r, err) return } defer tx.Rollback() user, err := db.GetUser(tx, u.Name) if err != nil { if db.IsNotFound(err) { http.Error(w, "User not found", http.StatusNotFound) } else { app.dbError(w, r, err) } return } viewUser := struct { Name string Email string Admin bool Apikey string }{user.Name, user.Email, user.Admin, user.Apikey} app.writeJson(w, &viewUser) }
func (app *App) handleLogin(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": app.serveFile("login.html").ServeHTTP(w, r) case "POST": username := r.FormValue("username") password := r.FormValue("password") if username == "" { http.Error(w, "No username provided", http.StatusBadRequest) return } if password == "" { http.Error(w, "No password provided", http.StatusBadRequest) return } tx, err := app.db.Begin() if err != nil { app.dbError(w, r, err) return } defer tx.Rollback() user, err := db.GetUser(tx, username) if err != nil { if db.IsNotFound(err) { http.Error(w, "User not found", http.StatusNotFound) } else { app.dbError(w, r, err) } return } if phash.Verify(password, user.Password) { u := &User{Id: user.Id, Name: user.Name} app.setUser(r, w, u) w.WriteHeader(http.StatusOK) } else { http.Error(w, "Invalid username passsword combination.", http.StatusBadRequest) } default: http.Error(w, "I only respond to GET and POSTs", http.StatusNotImplemented) } }
func (app *App) handleVerifyPassword(w http.ResponseWriter, r *http.Request) { switch r.Method { case "POST": // user should already be logged in, we're just validating the password password := r.FormValue("password") sessionUser, ok := app.getUser(r) if !ok { http.Error(w, "No user logged in", http.StatusBadRequest) return } tx, err := app.db.Begin() if err != nil { app.dbError(w, r, err) return } defer tx.Rollback() user, err := db.GetUser(tx, sessionUser.Name) if err != nil { if db.IsNotFound(err) { http.Error(w, "User not found", http.StatusNotFound) } else { app.dbError(w, r, err) } return } if password == "" { http.Error(w, "No password provided", http.StatusBadRequest) return } if phash.Verify(password, user.Password) { w.WriteHeader(http.StatusOK) } else { http.Error(w, "Invalid username passsword combination.", http.StatusBadRequest) } default: http.Error(w, "I only respond to POSTs", http.StatusNotImplemented) } }
// handleOldVerify handles the the /verify route hit by the R and Python // clients. func (app *App) handleOldVerify(w http.ResponseWriter, r *http.Request) { username, apikey, ok := r.BasicAuth() if !ok || username == "" { username = r.FormValue("username") apikey = r.FormValue("apikey") } if username == "" { http.Error(w, "No auth provided", http.StatusUnauthorized) return } tx, err := app.db.Begin() if err != nil { app.dbError(w, r, err) return } defer tx.Rollback() user, err := db.GetUser(tx, username) if err != nil { if db.IsNotFound(err) { w.WriteHeader(http.StatusNotFound) w.Write([]byte("user not found")) app.logf("authentication failed %s:%s", username, apikey) } else { app.dbError(w, r, err) } return } if apikey != user.Apikey { app.logf("authentication failed %s:%s", username, apikey) http.Error(w, "APIKEY did not match", http.StatusUnauthorized) return } w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"success": "true"}`)) }
func (app *App) handleWhoami(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": user, ok := app.getUser(r) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } tx, err := app.db.Begin() if err != nil { app.dbError(w, r, err) return } defer tx.Rollback() u, err := db.GetUser(tx, user.Name) if err != nil { app.dbError(w, r, err) return } resp := struct { Username string `json:"username"` Apikey string `json:"apikey"` ReadOnlyApikey string `json:"read_only_apikey"` }{user.Name, u.Apikey, u.ReadOnlyApikey} data, err := json.Marshal(&resp) if err != nil { http.Error(w, "Unrecognized internal error", 500) app.logf("could not encode json: %v", err) return } w.Write(data) default: http.Error(w, "I only respond to GETs", http.StatusNotImplemented) } }
// handleDeployment listens on the /deployer route and handles requests // from the R and Python clients. func (app *App) handleDeployment(w http.ResponseWriter, r *http.Request) { // for phone home metrics start := time.Now() username, apikey, ok := r.BasicAuth() if !ok || username == "" { username = r.FormValue("username") apikey = r.FormValue("apikey") } if username == "" { http.Error(w, "No auth provided", http.StatusUnauthorized) return } tx, err := app.db.Begin() if err != nil { app.dbError(w, r, err) return } defer tx.Rollback() user, err := db.GetUser(tx, username) if err != nil { if db.IsNotFound(err) { w.WriteHeader(http.StatusNotFound) w.Write([]byte("user not found")) } else { app.dbError(w, r, err) } return } if apikey != user.Apikey { http.Error(w, "APIKEY did not match", http.StatusUnauthorized) return } info, bundle, err := mps.ReadBundle(r) if err != nil { http.Error(w, "Could not parse upload request "+err.Error(), http.StatusBadRequest) return } modelSize := int64(len(bundle)) // validate model info if !isValidModelName(info.Modelname) { http.Error(w, fmt.Sprintf("'%s' is an invalid model name", info.Modelname), http.StatusBadRequest) return } // Write bundle to disk timestamp := time.Now().UTC().Format("2006_01_02_15_04_05") bundleFilename := user.Name + "_" + info.Modelname + "_" + timestamp + ".json" b := filepath.Join(app.bundleDir, bundleFilename) log.Println(b) if err := ioutil.WriteFile(b, bundle, 0644); err != nil { http.Error(w, fmt.Sprintf("could not write model file to disk %v", err), http.StatusInternalServerError) return } // add bundle to database p := db.NewVersionParams{ UserId: user.Id, Model: info.Modelname, Lang: info.Lang, LangPackages: info.LanguagePackages, UbuntuPackages: info.UbuntuPackages, SourceCode: info.SourceCode, BundleFilename: bundleFilename, } versionNum, err := db.NewModelVersion(tx, &p) if err != nil { http.Error(w, "could not create new model version: "+err.Error(), http.StatusInternalServerError) return } if err := tx.Commit(); err != nil { app.dbError(w, r, err) return } clientIP := r.RemoteAddr go func(user, model string, version int) { app.logf("deployment of %s:%s:%d started", user, model, version) err := app.sup.Deploy(user, model, version) if err != nil { app.logf("deployment of %s:%s:%d failed %v", user, model, version, err) } else { app.logf("deployment of %s:%s:%d succeeded", user, model, version) } if app.isdev { return } // Send phone home metrics errmsg := "" if err != nil { errmsg = err.Error() } d := &events.Deployment{ StartTime: start.Unix(), EndTime: time.Now().Unix(), Username: user, ModelName: model, ModelLang: info.Lang, ModelVer: int64(version), Service: app.serviceName, ClientIP: clientIP, Error: errmsg, ModelSize: modelSize, ModelDeps: packages(info.LanguagePackages).String(), } data, err := json.Marshal(&d) if err != nil { app.logf("could not marshal deployment: %v", err) return } resp, err := http.Post(events.Endpoint, "application/json", bytes.NewReader(data)) if err != nil { app.logf("failed to make request: %v", err) return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, err := ioutil.ReadAll(resp.Body) if err != nil { app.logf("could not read body: %v", err) return } app.logf("could not send info: %s %v", resp.Status, body) } }(user.Name, info.Modelname, versionNum) // send a JSON response to the user resp := struct { Status string `json:"status"` Version int `json:"version"` }{"Successfully deployed", versionNum} data, err := json.Marshal(&resp) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(data) }