1
0
Fork 0

Lay out API prototype and comment handlers a bit

master
Dario Ernst 8 years ago
parent b7b508d703
commit 6da7a2b57a

@ -7,9 +7,11 @@ import (
"crypto/rand" "crypto/rand"
"reflect" "reflect"
"log" "log"
"os"
// muxer and form parser // muxer and form parser
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/gorilla/handlers"
"github.com/gorilla/schema" "github.com/gorilla/schema"
// error returns for HandlerFunc // error returns for HandlerFunc
@ -72,28 +74,33 @@ func getToken(w http.ResponseWriter, r *http.Request) error {
var userInput User var userInput User
var userRecord User var userRecord User
var err error var err error
decoder := schema.NewDecoder() decoder := schema.NewDecoder()
// Parse form data
err = r.ParseForm() err = r.ParseForm()
if err != nil { if err != nil {
return ehttp.NewErrorf(http.StatusInternalServerError, "could not parse form", err) 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 { if err != nil {
return ehttp.NewErrorf(http.StatusInternalServerError, "could not decode user from form", err) return ehttp.NewErrorf(http.StatusInternalServerError, "could not decode user from form", err)
} }
// Find user in DB
db.First(&userRecord) db.First(&userRecord)
if db.Error != nil { if db.Error != nil {
return ehttp.NewErrorf(http.StatusInternalServerError, "database lookup error", err) 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) hash, err := scrypt.Key([]byte(userInput.Pass), []byte(userRecord.Salt), 16384, 8, 1, 32)
if err != nil { if err != nil {
return ehttp.NewErrorf(http.StatusInternalServerError, "cannot hash pass", err) return ehttp.NewErrorf(http.StatusInternalServerError, "cannot hash pass", err)
} }
if userRecord.Name == userInput.Name && reflect.DeepEqual(hash, []byte(userRecord.Pass)) { if userRecord.Name == userInput.Name && reflect.DeepEqual(hash, []byte(userRecord.Pass)) {
// Generate JWT-token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"name":userRecord.Name, "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) 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}) jsonOut, _ := json.Marshal(map[string]string{"token": tokenString})
fmt.Fprint(w, string(jsonOut)) fmt.Fprint(w, string(jsonOut))
return nil return nil
} }
// User was not found
return ehttp.NewErrorf(http.StatusForbidden, "Could not find user/pass") return ehttp.NewErrorf(http.StatusForbidden, "Could not find user/pass")
} }
func register(w http.ResponseWriter, r *http.Request) error { func register(w http.ResponseWriter, r *http.Request) error {
decoder := schema.NewDecoder() decoder := schema.NewDecoder()
// Parse http request to request-struct
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
return ehttp.NewErrorf(http.StatusInternalServerError, "could not parse form", err) return ehttp.NewErrorf(http.StatusInternalServerError, "could not parse form", err)
} }
// Decode request into struct
var input User var input User
err = decoder.Decode(&input, r.PostForm) err = decoder.Decode(&input, r.PostForm)
if err != nil { if err != nil {
return ehttp.NewErrorf(http.StatusInternalServerError, "could not decode user", err) return ehttp.NewErrorf(http.StatusInternalServerError, "could not decode user", err)
} }
// Validate struct
res, err := govalidator.ValidateStruct(input) res, err := govalidator.ValidateStruct(input)
if err != nil || res != true { if err != nil || res != true {
return ehttp.NewErrorf(http.StatusBadRequest, "could not validate your data", err) return ehttp.NewErrorf(http.StatusBadRequest, "could not validate your data", err)
} }
// Check if users already exists
countName := 0; countEmail := 0 countName := 0; countEmail := 0
db.Model(&User{}).Where("name = ?", input.Name).Count(&countName) db.Model(&User{}).Where("name = ?", input.Name).Count(&countName)
db.Model(&User{}).Where("email = ?", input.Email).Count(&countEmail) db.Model(&User{}).Where("email = ?", input.Email).Count(&countEmail)
log.Println("have countName", countName, "mail", countEmail)
if countName != 0 || countEmail != 0{ if countName != 0 || countEmail != 0{
return ehttp.NewErrorf(http.StatusConflict, "username or email already exists") return ehttp.NewErrorf(http.StatusConflict, "username or email already exists")
} }
// Generate salt
salt := make([]byte, 64) salt := make([]byte, 64)
_, err = rand.Read(salt) _, err = rand.Read(salt)
if err != nil { if err != nil {
@ -144,11 +157,14 @@ func register(w http.ResponseWriter, r *http.Request) error {
} }
input.Salt = string(salt) input.Salt = string(salt)
// Generate scrypt hash of pass
hash, err := scrypt.Key([]byte(input.Pass), salt, 16384, 8, 1, 32) hash, err := scrypt.Key([]byte(input.Pass), salt, 16384, 8, 1, 32)
if err != nil { if err != nil {
return ehttp.NewErrorf(http.StatusInternalServerError, "could not hash pass", err) return ehttp.NewErrorf(http.StatusInternalServerError, "could not hash pass", err)
} }
input.Pass = string(hash) input.Pass = string(hash)
// add to database
ret := db.NewRecord(input) ret := db.NewRecord(input)
if ret != true { if ret != true {
return ehttp.NewErrorf(http.StatusInternalServerError, "could not create user", err) return ehttp.NewErrorf(http.StatusInternalServerError, "could not create user", err)
@ -182,10 +198,33 @@ func main() {
// define URL handlers // define URL handlers
r := mux.NewRouter() 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) http.ListenAndServe(":8000", nil)
} }

Loading…
Cancel
Save