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