From 6da7a2b57a3cafd56f73fa5af5ff158c08849dd2 Mon Sep 17 00:00:00 2001 From: Dario Ernst Date: Thu, 3 Aug 2017 16:02:41 +0200 Subject: [PATCH] Lay out API prototype and comment handlers a bit --- server/main.go | 53 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/server/main.go b/server/main.go index e7e31bd..77882ce 100644 --- a/server/main.go +++ b/server/main.go @@ -7,9 +7,11 @@ import ( "crypto/rand" "reflect" "log" + "os" // muxer and form parser "github.com/gorilla/mux" + "github.com/gorilla/handlers" "github.com/gorilla/schema" // error returns for HandlerFunc @@ -72,28 +74,33 @@ func getToken(w http.ResponseWriter, r *http.Request) error { var userInput User var userRecord User var err error - decoder := schema.NewDecoder() + + // Parse form data err = r.ParseForm() if err != nil { return ehttp.NewErrorf(http.StatusInternalServerError, "could not parse form", err) } - err = decoder.Decode(&userInput, r.PostForm) + // Decode to struct + err = decoder.Decode(&userInput, r.Form) if err != nil { return ehttp.NewErrorf(http.StatusInternalServerError, "could not decode user from form", err) } + // Find user in DB db.First(&userRecord) if db.Error != nil { return ehttp.NewErrorf(http.StatusInternalServerError, "database lookup error", err) } + // Check hashed PW hash, err := scrypt.Key([]byte(userInput.Pass), []byte(userRecord.Salt), 16384, 8, 1, 32) if err != nil { return ehttp.NewErrorf(http.StatusInternalServerError, "cannot hash pass", err) } if userRecord.Name == userInput.Name && reflect.DeepEqual(hash, []byte(userRecord.Pass)) { + // Generate JWT-token token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "name":userRecord.Name, }) @@ -102,41 +109,47 @@ func getToken(w http.ResponseWriter, r *http.Request) error { return ehttp.NewErrorf(http.StatusForbidden, "could not construct token", err) } - log.Println("authenticated user", userRecord.Name, "with token", tokenString) + // Reply with token jsonOut, _ := json.Marshal(map[string]string{"token": tokenString}) fmt.Fprint(w, string(jsonOut)) return nil } + // User was not found return ehttp.NewErrorf(http.StatusForbidden, "Could not find user/pass") } func register(w http.ResponseWriter, r *http.Request) error { decoder := schema.NewDecoder() + + // Parse http request to request-struct err := r.ParseForm() if err != nil { return ehttp.NewErrorf(http.StatusInternalServerError, "could not parse form", err) } + // Decode request into struct var input User err = decoder.Decode(&input, r.PostForm) if err != nil { return ehttp.NewErrorf(http.StatusInternalServerError, "could not decode user", err) } + // Validate struct res, err := govalidator.ValidateStruct(input) if err != nil || res != true { return ehttp.NewErrorf(http.StatusBadRequest, "could not validate your data", err) } + // Check if users already exists countName := 0; countEmail := 0 db.Model(&User{}).Where("name = ?", input.Name).Count(&countName) db.Model(&User{}).Where("email = ?", input.Email).Count(&countEmail) - log.Println("have countName", countName, "mail", countEmail) if countName != 0 || countEmail != 0{ return ehttp.NewErrorf(http.StatusConflict, "username or email already exists") } + // Generate salt salt := make([]byte, 64) _, err = rand.Read(salt) if err != nil { @@ -144,11 +157,14 @@ func register(w http.ResponseWriter, r *http.Request) error { } input.Salt = string(salt) + // Generate scrypt hash of pass hash, err := scrypt.Key([]byte(input.Pass), salt, 16384, 8, 1, 32) if err != nil { return ehttp.NewErrorf(http.StatusInternalServerError, "could not hash pass", err) } input.Pass = string(hash) + + // add to database ret := db.NewRecord(input) if ret != true { return ehttp.NewErrorf(http.StatusInternalServerError, "could not create user", err) @@ -182,10 +198,33 @@ func main() { // define URL handlers r := mux.NewRouter() - r.Handle("/getToken", ehttp.HandlerFunc(getToken)) - r.Handle("/register", ehttp.HandlerFunc(register)) - http.Handle("/", r) + // User Management + r.Handle("/users", ehttp.HandlerFunc(register)).Methods("POST") // Make new user + r.Handle("/users", ehttp.HandlerFunc(getToken)).Methods("GET") // Get user „info“(=token) + // TODO: delete, modify + + // List Management + r.Handle("/lists", ehttp.HandlerFunc(nil)).Methods("POST") // Make a new list + r.Handle("/lists", ehttp.HandlerFunc(nil)).Methods("GET") // Get list of lists + r.Handle("/lists/{name}", ehttp.HandlerFunc(nil)).Methods("PUT") // Update list (name, icon, …) + r.Handle("/lists/{name}", ehttp.HandlerFunc(nil)).Methods("DELETE") // Delete a list + r.Handle("/lists/{name}", ehttp.HandlerFunc(nil)).Methods("GET") // Get list content (i.e., items) + // List sharing + r.Handle("/lists/{name}/sharers", ehttp.HandlerFunc(nil)).Methods("POST") // Add new sharer + r.Handle("/lists/{name}/sharers", ehttp.HandlerFunc(nil)).Methods("GET") // Get list of sharers + r.Handle("/lists/{name}/sharers/{user}", ehttp.HandlerFunc(nil)).Methods("DELETE") // Remove sharer + + r.Handle("/lists/{name}/items", ehttp.HandlerFunc(nil)).Methods("PUT") // Add new item + r.Handle("/lists/{name}/items/{item}", ehttp.HandlerFunc(nil)).Methods("DELETE") // Delete item + r.Handle("/lists/{name}/items/{item}", ehttp.HandlerFunc(nil)).Methods("POST") // Update item + + // Unit-history (unit is a ever-growing list only used for auto-completion) + r.Handle("/units", ehttp.HandlerFunc(nil)).Methods("POST") // Make a new unit + r.Handle("/units", ehttp.HandlerFunc(nil)).Methods("GET") // Get list of units + + loggedRouter := handlers.LoggingHandler(os.Stdout, r) + http.Handle("/", loggedRouter) http.ListenAndServe(":8000", nil) }