You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
4.7 KiB
Go

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 + `"}`))
}