package login import ( "bytes" "encoding/json" "fmt" "io/ioutil" "net/http" "os" "time" "golang.org/x/crypto/bcrypt" ) func SetUpHandlers() { http.HandleFunc("/register", registerHandler) http.HandleFunc("/login", loginHandler) http.HandleFunc("/users", usersHandler) http.HandleFunc("/auth", authHandler) } func registerHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Content-Type", "application/json") login, ok := decodeLogin(&w, &r) if !ok { return } if message, ok := validateRegistration(login); !ok { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(message)) return } hash, err := hashPassword(login.Password) if err != nil { fmt.Fprintln(os.Stderr, "Error hashing password:", err.Error()) w.WriteHeader(http.StatusInternalServerError) return } id, sessionId, err := newSession(login.Username) if err != nil { return } user := User{login.Username, sessionId, hash} jsonData, err := json.Marshal(user) if err != nil { fmt.Println("Error marshalling data") w.WriteHeader(http.StatusBadRequest) return } res, err := http.Post(DbAddress+"/user", "application/json", bytes.NewBuffer(jsonData)) if err != nil { fmt.Fprintln(os.Stderr, "Error adding user to db server:", err.Error()) w.WriteHeader(http.StatusInternalServerError) return } if mess, ok := checkBody(&res); !ok { w.WriteHeader(res.StatusCode) w.Write(mess) return } if mess, ok := storeSessionToken(login.Username, sessionId); !ok { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(mess)) return } c := &http.Cookie{HttpOnly: true, Name: "session", Value: sessionId, Expires: time.Now().Add(time.Hour * 24 * 30)} http.SetCookie(w, c) w.WriteHeader(http.StatusCreated) w.Write([]byte(`{"token":"` + id + `"}`)) } func loginHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Content-Type", "application/json") login, ok := decodeLogin(&w, &r) if !ok { return } res, err := http.Get(DbAddress + "/user?username=" + login.Username) if err != nil { fmt.Fprintln(os.Stderr, "db server error:", err.Error()) return } body, ok := checkBody(&res) if !ok { w.WriteHeader(res.StatusCode) w.Write(body) return } var user User if err := json.Unmarshal(body, &user); err != nil { fmt.Fprintln(os.Stderr, "bad user retrieved from db server:", string(body)) w.WriteHeader(http.StatusInternalServerError) return } if err := bcrypt.CompareHashAndPassword(user.HashedPassword, []byte(login.Password)); err != nil { fmt.Println("Failed login for user", login.Username) w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(`{"error":"login failed"}`)) return } id, sessionId, err := newSession(login.Username) if err != nil { return } if mess, ok := storeSessionToken(login.Username, sessionId); !ok { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(mess)) return } c := &http.Cookie{HttpOnly: true, Name: "session", Value: sessionId} http.SetCookie(w, c) w.WriteHeader(http.StatusOK) w.Write([]byte(`{"token":"` + id + `"}`)) } func usersHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") if r.Method != "GET" { w.WriteHeader(http.StatusMethodNotAllowed) return } if res, err := http.Get(DbAddress + "/users"); err != nil { fmt.Fprintln(os.Stderr, "db GET /users error:", err.Error()) } else { body, err := ioutil.ReadAll(res.Body) if err != nil { fmt.Fprintln(os.Stderr, "error reading response body:", err) } w.WriteHeader(res.StatusCode) w.Write(body) } } func authHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") if r.Method != "GET" { w.WriteHeader(http.StatusMethodNotAllowed) } val, err := r.Cookie("session") if err != nil { w.WriteHeader(http.StatusBadRequest) return } _, _, ok := retrieveSessionToken(val.Value) if !ok { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(`{"error":"token invalid"}`)) return } user, ok := getUserBySession(val.Value) if !ok { fmt.Println("not found") w.WriteHeader(http.StatusNotFound) return } id, sessionId, err := newSession(user.Username) if err != nil { return } if mess, ok := storeSessionToken(user.Username, sessionId); !ok { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(mess)) return } c := &http.Cookie{HttpOnly: true, Name: "session", Value: sessionId, Expires: time.Now().Add(time.Hour * 24 * 30)} http.SetCookie(w, c) w.Write([]byte(`{"token":"` + id + `"}`)) }