Skip to content

Commit

Permalink
feat: implemented /change-password (#186)
Browse files Browse the repository at this point in the history
Co-authored-by: Garrett Ladley <[email protected]>
  • Loading branch information
DOOduneye and garrettladley authored Feb 11, 2024
1 parent ccbbe09 commit ca7841b
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 1 deletion.
2 changes: 1 addition & 1 deletion backend/src/auth/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func CreateAccessToken(id string, role string, accessExpiresAfter uint, accessTo
StandardClaims: jwt.StandardClaims{
IssuedAt: time.Now().Unix(),
Issuer: id,
ExpiresAt: time.Now().Add(time.Hour * time.Duration(accessExpiresAfter)).Unix(),
ExpiresAt: time.Now().Add(time.Minute * time.Duration(accessExpiresAfter)).Unix(),
},
Role: role,
})
Expand Down
33 changes: 33 additions & 0 deletions backend/src/controllers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,36 @@ func (a *AuthController) Logout(c *fiber.Ctx) error {

return utilities.FiberMessage(c, fiber.StatusOK, "success")
}

// UpdatePassword godoc
//
// @Summary Updates a user's password
// @Description Updates a user's password
// @ID update-password
// @Tags user
// @Accept json
// @Produce json
// @Param userBody body []string true "User Body"
// @Success 200 {object} string "success"
// @Failure 400 {string} string "failed to parse body"
// @Failure 401 {string} string "failed to update password"
// @Router /api/v1/auth/update-password [post]
func (a *AuthController) UpdatePassword(c *fiber.Ctx) error {
var userBody models.UpdatePasswordRequestBody

if err := c.BodyParser(&userBody); err != nil {
return errors.FailedToParseRequestBody.FiberError(c)
}

claims, err := types.From(c)
if err != nil {
return err.FiberError(c)
}

err = a.authService.UpdatePassword(claims.Issuer, userBody)
if err != nil {
return err.FiberError(c)
}

return utilities.FiberMessage(c, fiber.StatusOK, "success")
}
5 changes: 5 additions & 0 deletions backend/src/models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ type LoginUserResponseBody struct {
Password string `json:"password" validate:"min=8,max=255"`
}

type UpdatePasswordRequestBody struct {
OldPassword string `json:"old_password" validate:"required,password"`
NewPassword string `json:"new_password" validate:"required,password"`
}

type CreateUserTagsBody struct {
Tags []uuid.UUID `json:"tags" validate:"required"`
}
1 change: 1 addition & 0 deletions backend/src/server/routes/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ func Auth(router fiber.Router, authService services.AuthServiceInterface, authSe
auth.Get("/logout", authController.Logout)
auth.Get("/refresh", authController.Refresh)
auth.Get("/me", authController.Me)
auth.Post("/update-password", authController.UpdatePassword)
}
42 changes: 42 additions & 0 deletions backend/src/services/auth.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package services

import (
"fmt"

"github.com/GenerateNU/sac/backend/src/auth"
"github.com/GenerateNU/sac/backend/src/errors"
"github.com/GenerateNU/sac/backend/src/models"
Expand All @@ -14,6 +16,7 @@ type AuthServiceInterface interface {
GetRole(id string) (*models.UserRole, *errors.Error)
Me(id string) (*models.User, *errors.Error)
Login(userBody models.LoginUserResponseBody) (*models.User, *errors.Error)
UpdatePassword(id string, userBody models.UpdatePasswordRequestBody) *errors.Error
}

type AuthService struct {
Expand Down Expand Up @@ -79,3 +82,42 @@ func (a *AuthService) GetRole(id string) (*models.UserRole, *errors.Error) {

return &role, nil
}

func (a *AuthService) UpdatePassword(id string, userBody models.UpdatePasswordRequestBody) *errors.Error {
idAsUint, idErr := utilities.ValidateID(id)
if idErr != nil {
return idErr
}

// TODO: Validate password
// if err := a.Validate.Struct(userBody); err != nil {
// return &errors.FailedToValidateUser
// }

passwordHash, err := transactions.GetUserPasswordHash(a.DB, *idAsUint)
if err != nil {
return &errors.UserNotFound
}

correct, passwordErr := auth.ComparePasswordAndHash(userBody.OldPassword, passwordHash)
if passwordErr != nil {
fmt.Println("err", passwordErr)
return &errors.FailedToValidateUser
}

if !correct {
return &errors.FailedToValidateUser
}

hash, hashErr := auth.ComputePasswordHash(userBody.NewPassword)
if hashErr != nil {
return &errors.FailedToValidateUser
}

updateErr := transactions.UpdatePassword(a.DB, *idAsUint, *hash)
if updateErr != nil {
return updateErr
}

return nil
}
25 changes: 25 additions & 0 deletions backend/src/transactions/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ func GetUser(db *gorm.DB, id uuid.UUID) (*models.User, *errors.Error) {
return &user, nil
}

func GetUserPasswordHash(db *gorm.DB, id uuid.UUID) (string, *errors.Error) {
var user models.User
if err := db.Select("password_hash").First(&user, id).Error; err != nil {
if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
return "", &errors.UserNotFound
} else {
return "", &errors.FailedToGetUser
}
}

return user.PasswordHash, nil
}

func UpdateUser(db *gorm.DB, id uuid.UUID, user models.User) (*models.User, *errors.Error) {
var existingUser models.User

Expand All @@ -74,6 +87,18 @@ func UpdateUser(db *gorm.DB, id uuid.UUID, user models.User) (*models.User, *err
return &existingUser, nil
}

func UpdatePassword(db *gorm.DB, id uuid.UUID, passwordHash string) *errors.Error {
result := db.Model(&models.User{}).Where("id = ?", id).Update("password_hash", passwordHash)
if result.RowsAffected == 0 {
if result.Error == nil {
return &errors.UserNotFound
} else {
return &errors.FailedToUpdateUser
}
}
return nil
}

func DeleteUser(db *gorm.DB, id uuid.UUID) *errors.Error {
result := db.Delete(&models.User{}, id)
if result.RowsAffected == 0 {
Expand Down

0 comments on commit ca7841b

Please sign in to comment.