From c426332533c9f9786c403b338554753a5bc01891 Mon Sep 17 00:00:00 2001 From: Gaurav Mishra Date: Fri, 5 Jan 2024 13:56:50 +0530 Subject: [PATCH] feat(auth): user bcrypt to encrypt user password Signed-off-by: Gaurav Mishra --- pkg/auth/auth.go | 53 ++++++++++++++++++++++++++++++++++++++++++++++- pkg/utils/util.go | 25 ++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index ddde712..a911e38 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -13,6 +13,8 @@ import ( "strings" "time" + "golang.org/x/crypto/bcrypt" + "github.com/gin-gonic/gin" "github.com/fossology/LicenseDb/pkg/db" @@ -54,6 +56,19 @@ func CreateUser(c *gin.Context) { Userpassword: input.Userpassword, } + err := utils.HashPassword(&user) + if err != nil { + er := models.LicenseError{ + Status: http.StatusBadRequest, + Message: "password hashing failed", + Error: err.Error(), + Path: c.Request.URL.Path, + Timestamp: time.Now().Format(time.RFC3339), + } + c.JSON(http.StatusBadRequest, er) + return + } + result := db.DB.Where(models.User{Username: user.Username}).FirstOrCreate(&user) if result.Error != nil { er := models.LicenseError{ @@ -231,8 +246,24 @@ func AuthenticationMiddleware() gin.HandlerFunc { return } + err = EncryptUserPassword(&user) + if err != nil { + er := models.LicenseError{ + Status: http.StatusInternalServerError, + Message: "Failed to encrypt user password", + Error: err.Error(), + Path: c.Request.URL.Path, + Timestamp: time.Now().Format(time.RFC3339), + } + + c.JSON(http.StatusInternalServerError, er) + c.Abort() + return + } + // Check if the password matches - if *user.Userpassword != password { + err = utils.VerifyPassword(password, *user.Userpassword) + if err != nil { er := models.LicenseError{ Status: http.StatusUnauthorized, Message: "Incorrect password", @@ -266,3 +297,23 @@ func CORSMiddleware() gin.HandlerFunc { c.Next() } } + +// EncryptUserPassword checks if the password is already encrypted or not. If +// not, it encrypts the password. +func EncryptUserPassword(user *models.User) error { + _, err := bcrypt.Cost([]byte(*user.Userpassword)) + if err == nil { + return nil + } + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(*user.Userpassword), bcrypt.DefaultCost) + + if err != nil { + return err + } + *user.Userpassword = string(hashedPassword) + + db.DB.Model(&user).Updates(user) + + return nil +} diff --git a/pkg/utils/util.go b/pkg/utils/util.go index 14d5022..de71ccf 100644 --- a/pkg/utils/util.go +++ b/pkg/utils/util.go @@ -8,10 +8,14 @@ package utils import ( "fmt" + "html" "net/http" "strconv" + "strings" "time" + "golang.org/x/crypto/bcrypt" + "github.com/gin-gonic/gin" "github.com/fossology/LicenseDb/pkg/models" @@ -121,3 +125,24 @@ func ParseIdToInt(c *gin.Context, id string, idType string) (int64, error) { } return parsedId, nil } + +// HashPassword hashes the password of the user using bcrypt. It also trims the +// username and escapes the HTML characters. +func HashPassword(user *models.User) error { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(*user.Userpassword), bcrypt.DefaultCost) + + if err != nil { + return err + } + *user.Userpassword = string(hashedPassword) + + user.Username = html.EscapeString(strings.TrimSpace(user.Username)) + + return nil +} + +// VerifyPassword compares the input password with the password stored in the +// database. Returns nil on success, or an error on failure. +func VerifyPassword(inputPassword, dbPassword string) error { + return bcrypt.CompareHashAndPassword([]byte(dbPassword), []byte(inputPassword)) +}