From 0e0aa3b1d1b7dcfc2a1c129af158ae0cfa117e76 Mon Sep 17 00:00:00 2001 From: pahmiudahgede Date: Tue, 14 Jan 2025 04:13:14 +0700 Subject: [PATCH] fix: fixing login register method access --- domain/user.go | 4 +-- internal/controllers/auth.go | 27 ++++++++------ internal/repositories/auth.go | 44 +++++++++++------------ internal/services/auth.go | 68 ++++++++++++++++++++--------------- utils/role_permission.go | 8 ++--- 5 files changed, 84 insertions(+), 67 deletions(-) diff --git a/domain/user.go b/domain/user.go index 73d1bf2..075ead1 100644 --- a/domain/user.go +++ b/domain/user.go @@ -5,10 +5,10 @@ import "time" type User struct { ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"` Avatar *string `json:"avatar,omitempty"` - Username string `gorm:"unique;not null" json:"username"` + Username string `gorm:"not null" json:"username"` Name string `gorm:"not null" json:"name"` Phone string `gorm:"not null" json:"phone"` - Email string `gorm:"unique;not null" json:"email"` + Email string `gorm:"not null" json:"email"` EmailVerified bool `gorm:"default:false" json:"emailVerified"` Password string `gorm:"not null" json:"password"` Pin UserPin `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"pin"` diff --git a/internal/controllers/auth.go b/internal/controllers/auth.go index a663570..8f94b9c 100644 --- a/internal/controllers/auth.go +++ b/internal/controllers/auth.go @@ -29,14 +29,14 @@ func Register(c *fiber.Ctx) error { err := services.RegisterUser(userInput.Username, userInput.Name, userInput.Email, userInput.Phone, userInput.Password, userInput.ConfirmPassword, userInput.RoleId) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, + return c.Status(fiber.StatusConflict).JSON(utils.FormatResponse( + fiber.StatusConflict, err.Error(), nil, )) } - user, err := repositories.GetUserByEmailOrUsername(userInput.Email) + user, err := repositories.GetUserByEmailUsernameOrPhone(userInput.Email, userInput.RoleId) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( fiber.StatusInternalServerError, @@ -65,8 +65,8 @@ func Register(c *fiber.Ctx) error { func Login(c *fiber.Ctx) error { var credentials struct { - EmailOrUsername string `json:"email_or_username"` - Password string `json:"password"` + Identifier string `json:"identifier"` + Password string `json:"password"` } if err := c.BodyParser(&credentials); err != nil { @@ -77,7 +77,7 @@ func Login(c *fiber.Ctx) error { )) } - user, err := repositories.GetUserByEmailOrUsername(credentials.EmailOrUsername) + token, err := services.LoginUser(credentials.Identifier, credentials.Password) if err != nil { return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( fiber.StatusUnauthorized, @@ -86,7 +86,7 @@ func Login(c *fiber.Ctx) error { )) } - token, err := services.LoginUser(credentials.EmailOrUsername, credentials.Password) + user, err := repositories.GetUserByEmailUsernameOrPhone(credentials.Identifier, "") if err != nil { return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( fiber.StatusUnauthorized, @@ -154,12 +154,19 @@ func UpdateUser(c *fiber.Ctx) error { )) } - userID := c.Locals("userID").(string) + userID, ok := c.Locals("userID").(string) + if !ok || userID == "" { + return c.Status(fiber.StatusUnauthorized).JSON(utils.FormatResponse( + fiber.StatusUnauthorized, + "Unauthorized access", + nil, + )) + } err := services.UpdateUser(userID, userInput.Email, userInput.Username, userInput.Name, userInput.Phone) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse( - fiber.StatusInternalServerError, + return c.Status(fiber.StatusConflict).JSON(utils.FormatResponse( + fiber.StatusConflict, err.Error(), nil, )) diff --git a/internal/repositories/auth.go b/internal/repositories/auth.go index f4c8767..c4fb68f 100644 --- a/internal/repositories/auth.go +++ b/internal/repositories/auth.go @@ -8,44 +8,37 @@ import ( "github.com/pahmiudahgede/senggoldong/domain" ) -func IsEmailExist(email string) bool { +func IsEmailExist(email, roleId string) bool { var user domain.User if err := config.DB.Where("email = ?", email).First(&user).Error; err == nil { - return true + if user.RoleID == roleId { + return true + } } return false } -func IsUsernameExist(username string) bool { +func IsUsernameExist(username, roleId string) bool { var user domain.User if err := config.DB.Where("username = ?", username).First(&user).Error; err == nil { - return true + if user.RoleID == roleId { + return true + } } return false } -func IsPhoneExist(phone string) bool { +func IsPhoneExist(phone, roleId string) bool { var user domain.User if err := config.DB.Where("phone = ?", phone).First(&user).Error; err == nil { - return true + if user.RoleID == roleId { + return true + } } return false } func CreateUser(username, name, email, phone, password, roleId string) error { - - if IsEmailExist(email) { - return errors.New("email is already registered") - } - - if IsUsernameExist(username) { - return errors.New("username is already registered") - } - - if IsPhoneExist(phone) { - return errors.New("phone number is already registered") - } - user := domain.User{ Username: username, Name: name, @@ -62,11 +55,17 @@ func CreateUser(username, name, email, phone, password, roleId string) error { return nil } -func GetUserByEmailOrUsername(emailOrUsername string) (domain.User, error) { +func GetUserByEmailUsernameOrPhone(identifier, roleId string) (domain.User, error) { var user domain.User - if err := config.DB.Where("email = ? OR username = ?", emailOrUsername, emailOrUsername).First(&user).Error; err != nil { + err := config.DB.Where("email = ? OR username = ? OR phone = ?", identifier, identifier, identifier).First(&user).Error + if err != nil { return user, errors.New("user not found") } + + if roleId != "" && user.RoleID != roleId { + return user, errors.New("identifier found but role does not match") + } + return user, nil } @@ -85,8 +84,9 @@ func GetUserByID(userID string) (domain.User, error) { } func UpdateUser(user *domain.User) error { + if err := config.DB.Save(user).Error; err != nil { - return errors.New("failed to save user") + return errors.New("failed to update user") } return nil } diff --git a/internal/services/auth.go b/internal/services/auth.go index 2630679..6d0712e 100644 --- a/internal/services/auth.go +++ b/internal/services/auth.go @@ -12,18 +12,21 @@ import ( ) func RegisterUser(username, name, email, phone, password, confirmPassword, roleId string) error { + if password != confirmPassword { return errors.New("password dan confirm password tidak cocok") } - if repositories.IsEmailExist(email) { - return errors.New("email is already registered") + if repositories.IsEmailExist(email, roleId) { + return errors.New("email is already registered with the same role") } - if repositories.IsUsernameExist(username) { - return errors.New("username is already registered") + + if repositories.IsUsernameExist(username, roleId) { + return errors.New("username is already registered with the same role") } - if repositories.IsPhoneExist(phone) { - return errors.New("phone number is already registered") + + if repositories.IsPhoneExist(phone, roleId) { + return errors.New("phone number is already registered with the same role") } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) @@ -39,19 +42,21 @@ func RegisterUser(username, name, email, phone, password, confirmPassword, roleI return nil } -func LoginUser(emailOrUsername, password string) (string, error) { - if emailOrUsername == "" || password == "" { - return "", errors.New("email/username and password must be provided") +func LoginUser(identifier, password string) (string, error) { + if identifier == "" || password == "" { + return "", errors.New("email/username/phone and password must be provided") } - user, err := repositories.GetUserByEmailOrUsername(emailOrUsername) + const roleId = "" + + user, err := repositories.GetUserByEmailUsernameOrPhone(identifier, roleId) if err != nil { - return "", errors.New("invalid email/username or password") + return "", errors.New("invalid email/username/phone or password") } err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) if err != nil { - return "", errors.New("invalid email/username or password") + return "", errors.New("invalid email/username/phone or password") } token := generateJWT(user.ID, user.RoleID) @@ -90,30 +95,30 @@ func UpdateUser(userID, email, username, name, phone string) error { return errors.New("user not found") } - if email != "" && email != user.Email && repositories.IsEmailExist(email) { - return errors.New("email is already registered") - } - - if username != "" && username != user.Username && repositories.IsUsernameExist(username) { - return errors.New("username is already registered") - } - - if phone != "" && phone != user.Phone && repositories.IsPhoneExist(phone) { - return errors.New("phone number is already registered") - } - - if email != "" { + if email != "" && email != user.Email { + if repositories.IsEmailExist(email, user.RoleID) { + return errors.New("email is already registered with the same role") + } user.Email = email } - if username != "" { + + if username != "" && username != user.Username { + if repositories.IsUsernameExist(username, user.RoleID) { + return errors.New("username is already registered with the same role") + } user.Username = username } + + if phone != "" && phone != user.Phone { + if repositories.IsPhoneExist(phone, user.RoleID) { + return errors.New("phone number is already registered with the same role") + } + user.Phone = phone + } + if name != "" { user.Name = name } - if phone != "" { - user.Phone = phone - } err = repositories.UpdateUser(&user) if err != nil { @@ -135,6 +140,11 @@ func UpdatePassword(userID, oldPassword, newPassword string) error { return errors.New("old password is incorrect") } + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(newPassword)) + if err == nil { + return errors.New("new password cannot be the same as the old password") + } + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) if err != nil { return errors.New("failed to hash new password") diff --git a/utils/role_permission.go b/utils/role_permission.go index ac3ef25..51d59eb 100644 --- a/utils/role_permission.go +++ b/utils/role_permission.go @@ -1,8 +1,8 @@ package utils const ( - RoleMasyarakat = "3e8cd1f0-205c-488d-9bab-bb53b99a6f49" - RolePengepul = "88a756fd-e9ab-4257-83a6-c36a0fb944b1" - RolePengelola = "cb328d60-5d40-4404-bfe1-25224d1bd126" - RoleAdministrator = "229395a8-f26d-445b-ae53-c67e5b25ea03" + RoleMasyarakat = "63191315-c59f-4af9-91a7-367c698cc486" + RolePengepul = "bda3827a-3c61-459a-9a95-42e2bb88d737" + RolePengelola = "fc75351d-eded-4314-a41b-e4a901e6540c" + RoleAdministrator = "fe4a15ce-5a0c-40d0-9be0-a7d4b6d05480" )