package login import ( "bytes" "encoding/json" "fmt" "io/ioutil" "net/http" "os" "time" "github.com/golang-jwt/jwt" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" ) type Login struct { Username string `json:"username"` Password string `json:"password"` } type User struct { Username string `json:"username"` Session string `json:"session"` HashedPassword []byte `json:"hashedPassword"` } var JwtSecret = os.Getenv("secret") var Address = "127.0.0.1:8001" var DbAddress = "http://127.0.0.1:8002" func decodeLogin(w *http.ResponseWriter, r **http.Request) (login Login, ok bool) { (*w).Header().Set("Access-Control-Allow-Origin", "*") if (*r).Method == "OPTIONS" { return } if (*r).Method != "POST" { (*w).WriteHeader(http.StatusMethodNotAllowed) return Login{}, false } if err := json.NewDecoder((*r).Body).Decode(&login); err != nil { fmt.Println("Error decoding login", err.Error()) (*w).WriteHeader(http.StatusBadRequest) (*w).Write([]byte(`{"error":"malformed login"}`)) return Login{}, false } return login, true } func validateRegistration(login Login) (message string, ok bool) { const ( numLowerBound = 48 numUpperBound = 57 lcAlphaLowerBound = 97 lcAlphaUpperBound = 122 ucAlphaLowerBound = 65 ucAlphaUpperBound = 90 ) if len(login.Password) < 8 { message = `{"error":"password too short"}` return } var lcAlphaCount, ucAlphaCount, numCount, specialCount int for _, char := range login.Password { intVal := int(char) if numLowerBound <= intVal && intVal <= numUpperBound { numCount++ } else if lcAlphaLowerBound <= intVal && intVal <= lcAlphaUpperBound { lcAlphaCount++ } else if ucAlphaLowerBound <= intVal && intVal <= ucAlphaUpperBound { ucAlphaCount++ } else { specialCount++ } } if lcAlphaCount == 0 || ucAlphaCount == 0 || numCount == 0 || specialCount == 0 { message = `{"error":"password failed criteria"}` return } return "", true } func hashPassword(password string) (hash []byte, err error) { hash, err = bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { fmt.Fprintln(os.Stderr, "Error hashing password", err.Error()) } return } func checkBody(res **http.Response) (mess []byte, ok bool) { body, err := ioutil.ReadAll((*res).Body) if err != nil { fmt.Fprintln(os.Stderr, "error reading response body:", err) return nil, false } if (*res).StatusCode != http.StatusOK { fmt.Println(string(body)) return body, false } return body, true } func encodeJson(data interface{}) ([]byte, bool) { if jsonData, err := json.Marshal(data); err != nil { fmt.Fprintln(os.Stderr, "Could not marshal json data", data) return nil, false } else { return jsonData, true } } func createJWT(username string) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "exp": time.Now().Add(5 * time.Minute).Unix(), "username": username, }) tokenString, err := token.SignedString([]byte(JwtSecret)) return tokenString, err } func newSession(username string) (jwt, sessionId string, err error) { jwt, err = createJWT(username) return jwt, uuid.NewString(), err } func storeSessionToken(username, token string) (message string, ok bool) { user := User{username, token, nil} jsonData, ok := encodeJson(user) if !ok { return "error encoding json", false } res, err := http.Post(DbAddress+"/session", "application/json", bytes.NewBuffer(jsonData)) if err != nil { fmt.Fprintln(os.Stderr, "could not reach db server:", err) return "could not reach db server", false } body, err := ioutil.ReadAll(res.Body) if err != nil { return "could not decode response body", false } if err != nil || res.StatusCode != http.StatusOK { return string(body), false } return "", true } func retrieveSessionToken(username string) (token, message string, ok bool) { res, err := http.Get(DbAddress + "/session?username=" + username) if err != nil { fmt.Fprintln(os.Stderr, "could not reach db server:", err) return "", "could not reach db server", false } body, err := ioutil.ReadAll(res.Body) if err != nil || res.StatusCode != http.StatusOK { return "", string(body), false } var user User if err := json.Unmarshal(body, &user); err != nil { return "", err.Error(), false } return user.Session, "", true } func getUserBySession(session string) (user User, ok bool) { res, err := http.Get(DbAddress + "/user?session=" + session) if err != nil { fmt.Fprintln(os.Stderr, "error reaching db server", err.Error()) return User{}, false } if res.StatusCode != http.StatusOK { return User{}, false } body, err := ioutil.ReadAll(res.Body) if err != nil { fmt.Fprintln(os.Stderr, "could not read response body:", err) return User{}, false } if err := json.Unmarshal(body, &user); err != nil { fmt.Fprintln(os.Stderr, "unmarhsal user error", err.Error()) return user, false } return user, true }