From a79709e1ac8d612799c70059695b3e2460da898a Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Thu, 9 Feb 2023 01:07:31 -0300 Subject: [PATCH] allow user to change their password --- backend/controllers/user.go | 34 ++++++++++++++++++++++++++++++++-- backend/middlewares/auth.go | 11 ++++++++++- backend/models/user.go | 11 ++++++----- backend/utils/jwt.go | 2 +- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/backend/controllers/user.go b/backend/controllers/user.go index 0c6b724..270f9ee 100644 --- a/backend/controllers/user.go +++ b/backend/controllers/user.go @@ -2,10 +2,12 @@ package controllers import ( "encoding/json" + "errors" "net/http" "strconv" "git.cromer.cl/Proyecto-Titulo/alai-server/backend/database" + "git.cromer.cl/Proyecto-Titulo/alai-server/backend/middlewares" "git.cromer.cl/Proyecto-Titulo/alai-server/backend/models" "git.cromer.cl/Proyecto-Titulo/alai-server/backend/utils" @@ -103,6 +105,9 @@ func UpdateUser(writer http.ResponseWriter, request *http.Request, params httpro gdb := database.Connect() defer database.Close(gdb) + claims := request.Context().Value(middlewares.JWTContextKey).(*utils.JWTClaim) + username := claims.Username + var user models.User decoder := json.NewDecoder(request.Body) @@ -119,8 +124,33 @@ func UpdateUser(writer http.ResponseWriter, request *http.Request, params httpro return } - if user.Password != "" { - user.HashPassword(user.Password) + if user.NewPassword != "" { + var tmpUser models.User + + result := gdb.Find(&tmpUser).Where(&models.User{Username: username}) + if result.Error != nil { + utils.JSONErrorOutput(writer, http.StatusBadRequest, result.Error.Error()) + return + } else if result.RowsAffected == 0 { + writer.WriteHeader(http.StatusNotFound) + return + } + + // If the logged in user and the modified user are no the same, password can't be changed + if tmpUser.ID != user.ID { + utils.JSONErrorOutput(writer, http.StatusBadRequest, errors.New("only the same user may change password").Error()) + return + } + + err = tmpUser.CheckPassword(user.Password) + if err != nil { + utils.JSONErrorOutput(writer, http.StatusBadRequest, errors.New("incorrect user or password").Error()) + return + } + + user.HashPassword(user.NewPassword) + } else { + user.Password = "" } result := gdb.Updates(&user) diff --git a/backend/middlewares/auth.go b/backend/middlewares/auth.go index acd42d7..603150c 100644 --- a/backend/middlewares/auth.go +++ b/backend/middlewares/auth.go @@ -1,6 +1,7 @@ package middlewares import ( + "context" "errors" "net/http" "strings" @@ -10,6 +11,10 @@ import ( "github.com/julienschmidt/httprouter" ) +type contextKey string + +const JWTContextKey contextKey = "JWTClaims" + func Authenticate(handle httprouter.Handle) httprouter.Handle { return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) { reqToken := request.Header.Get("Authorization") @@ -20,12 +25,16 @@ func Authenticate(handle httprouter.Handle) httprouter.Handle { } tokenString := splitToken[1] - err := utils.ValidateToken(tokenString) + claims, err := utils.ValidateToken(tokenString) if err != nil { utils.JSONErrorOutput(writer, http.StatusUnauthorized, err.Error()) return } + ctx := request.Context() + ctx = context.WithValue(ctx, JWTContextKey, claims) + request = request.WithContext(ctx) + handle(writer, request, params) } } diff --git a/backend/models/user.go b/backend/models/user.go index 6253b0c..6e019b1 100644 --- a/backend/models/user.go +++ b/backend/models/user.go @@ -7,11 +7,12 @@ import ( type User struct { gorm.Model - ID uint64 `json:"ID" gorm:"primaryKey"` - Name string `json:"name" gorm:"not null"` - Username string `json:"username" gorm:"unique; not null"` - Email string `json:"email" gorm:"unique;not null"` - Password string `json:"password" gorm:"not null"` + ID uint64 `json:"ID" gorm:"primaryKey"` + Name string `json:"name" gorm:"not null"` + Username string `json:"username" gorm:"unique; not null"` + Email string `json:"email" gorm:"unique;not null"` + Password string `json:"password,omitempty" gorm:"not null"` + NewPassword string `json:"new_password,omitempty" gorm:"-:all"` } func (user *User) HashPassword(password string) error { diff --git a/backend/utils/jwt.go b/backend/utils/jwt.go index 22ec4ea..ad4d9fe 100644 --- a/backend/utils/jwt.go +++ b/backend/utils/jwt.go @@ -28,7 +28,7 @@ func GenerateJWT(email string, username string) (tokenString string, err error) return } -func ValidateToken(signedToken string) (err error) { +func ValidateToken(signedToken string) (claims *JWTClaim, err error) { token, err := jwt.ParseWithClaims( signedToken, &JWTClaim{},