package users import ( "encoding/json" "log" "net/http" "os" "time" "github.com/dustinpianalto/quartermaster" "github.com/dustinpianalto/quartermaster/pkg/services" "github.com/golang-jwt/jwt" "golang.org/x/crypto/bcrypt" ) var jwtKey = []byte(os.Getenv("JWT_KEY")) func login(w http.ResponseWriter, r *http.Request) { var userReq quartermaster.User err := json.NewDecoder(r.Body).Decode(&userReq) if err != nil { w.WriteHeader(http.StatusBadRequest) log.Println(err) return } user, err := services.UserService.User(userReq.Username) if err != nil { w.WriteHeader(http.StatusUnauthorized) log.Println(err) return } if bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(userReq.Password)) != nil { w.WriteHeader(http.StatusUnauthorized) log.Println(err) return } expires := time.Now().Add(10 * time.Minute) claims := &quartermaster.Claims{ ID: user.ID, Username: user.Username, StandardClaims: jwt.StandardClaims{ ExpiresAt: expires.Unix(), }, } token := jwt.NewWithClaims(jwt.SigningMethodHS512, claims) tokenString, err := token.SignedString(jwtKey) if err != nil { w.WriteHeader(http.StatusInternalServerError) log.Println(err) return } http.SetCookie(w, &http.Cookie{ Name: "token", Value: tokenString, Expires: expires, }) } func register(w http.ResponseWriter, r *http.Request) { var user *quartermaster.User err := json.NewDecoder(r.Body).Decode(&user) if err != nil { w.WriteHeader(http.StatusBadRequest) return } p, err := bcrypt.GenerateFromPassword([]byte(user.Password), 5) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } user.Password = string(p) user, err = services.UserService.AddUser(user) if err != nil { w.WriteHeader(http.StatusConflict) log.Println(err) return } } func refresh(w http.ResponseWriter, r *http.Request) { c, err := r.Cookie("token") if err != nil { if err == http.ErrNoCookie { w.WriteHeader(http.StatusUnauthorized) return } w.WriteHeader(http.StatusBadRequest) return } tknStr := c.Value claims := &quartermaster.Claims{} tkn, err := jwt.ParseWithClaims(tknStr, claims, func(token *jwt.Token) (interface{}, error) { return jwtKey, nil }) if err != nil { if err == jwt.ErrSignatureInvalid { w.WriteHeader(http.StatusUnauthorized) return } w.WriteHeader(http.StatusBadRequest) return } if !tkn.Valid { w.WriteHeader(http.StatusUnauthorized) return } // We ensure that a new token is not issued until enough time has elapsed // In this case, a new token will only be issued if the old token is within // 2 minutes of expiry. Otherwise, return a bad request status if time.Until(time.Unix(claims.StandardClaims.ExpiresAt, 0)) >= 2*time.Minute { w.WriteHeader(http.StatusBadRequest) return } // Now, create a new token for the current use, with a renewed expiration time expirationTime := time.Now().Add(10 * time.Minute) claims.StandardClaims.ExpiresAt = expirationTime.Unix() token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString(jwtKey) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } // Set the new token as the users `token` cookie http.SetCookie(w, &http.Cookie{ Name: "token", Value: tokenString, Expires: expirationTime, }) }