From 63735806c1bd3e59dbe1cd4f5b73839d53f75642 Mon Sep 17 00:00:00 2001 From: PavanCodes05 Date: Thu, 30 Oct 2025 20:41:10 +0530 Subject: [PATCH 1/3] feat: add bcrypt encryption for registration - Import bcrpyt lib - Hash password before inserting to db - Insert hashed password to db --- modules/register/verify.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/register/verify.go b/modules/register/verify.go index c1f3395..c80cd4e 100644 --- a/modules/register/verify.go +++ b/modules/register/verify.go @@ -7,6 +7,8 @@ import ( "evolve/util" dbutil "evolve/util/db/user" "fmt" + + "golang.org/x/crypto/bcrypt" ) type VerifyReq struct { @@ -63,8 +65,14 @@ func (r *VerifyReq) Verify(ctx context.Context, user map[string]string) error { return fmt.Errorf("invalid otp") } + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user["password"]), bcrypt.DefaultCost) + if err != nil { + logger.Error(fmt.Sprintf("RegisterVerify: failed to hash password: %v", err), err) + return fmt.Errorf("something went wrong") + } + // Insert user into user table. - if _, err := db.Exec(ctx, "INSERT INTO users (email, userName, fullName, password) VALUES($1, $2, $3, $4)", user["email"], user["userName"], user["fullName"], user["password"]); err != nil { + if _, err := db.Exec(ctx, "INSERT INTO users (email, userName, fullName, password) VALUES($1, $2, $3, $4)", user["email"], user["userName"], user["fullName"], string(hashedPassword)); err != nil { logger.Error(fmt.Sprintf("RegisterVerify: failed to insert into users: %v", err), err) return fmt.Errorf("something went wrong") } From bf884ea8cda5e727b51529fdb15a444ac18f7a40 Mon Sep 17 00:00:00 2001 From: PavanCodes05 Date: Thu, 30 Oct 2025 20:50:27 +0530 Subject: [PATCH 2/3] feat: add bcrypt encryption for login - Import bcrypt lib - Get user and password hash - Verify password with hash --- modules/login.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/login.go b/modules/login.go index d58d5af..48ad392 100644 --- a/modules/login.go +++ b/modules/login.go @@ -10,6 +10,7 @@ import ( "fmt" "github.com/google/uuid" + "golang.org/x/crypto/bcrypt" ) type LoginReq struct { @@ -59,15 +60,26 @@ func (l *LoginReq) Login(ctx context.Context) (map[string]string, error) { } // id is UUID(16 bytes) Google's UUID. + // Query user and get password hash var id uuid.UUID var role string + var storedPasswordHash string + err = db.QueryRow(ctx, "SELECT id, role, password FROM users WHERE username = $1 OR email = $2", l.UserName, l.Email).Scan(&id, &role, &storedPasswordHash) - err = db.QueryRow(ctx, "SELECT id, role FROM users WHERE (username = $1 OR email = $2) AND password = $3", l.UserName, l.Email, l.Password).Scan(&id, &role) if err != nil { logger.Error(fmt.Sprintf("Login: failed to query user: %v", err), err) return nil, fmt.Errorf("invalid username/email or password") } + // Verify password using bcrypt + err = bcrypt.CompareHashAndPassword([]byte(storedPasswordHash), []byte(l.Password)) + if err != nil { + // Password doesn't match + logger.Info("Login: invalid password attempt") + return nil, fmt.Errorf("invalid username/email or password") + } + + // Password verified, get user details user, err := dbutil.UserById(ctx, id.String(), db) if err != nil { logger.Error(fmt.Sprintf("Login: failed to get user by id: %v", err), err) From 5bfcd30fea9d4f40203b101e520a735b6e789ca1 Mon Sep 17 00:00:00 2001 From: PavanCodes05 Date: Thu, 30 Oct 2025 21:38:24 +0530 Subject: [PATCH 3/3] feat: enhance login flow with bcrypt support and legacy password upgrade - Added bcrypt hash detection via helper - Implemented secure password comparison and rehashing for legacy users --- modules/login.go | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/modules/login.go b/modules/login.go index 48ad392..b9c4f62 100644 --- a/modules/login.go +++ b/modules/login.go @@ -8,6 +8,7 @@ import ( "evolve/util/auth" dbutil "evolve/util/db/user" "fmt" + "strings" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" @@ -46,6 +47,12 @@ func (l *LoginReq) validate() error { return nil } +func isBcryptHash(s string) bool { + return strings.HasPrefix(s, "$2a$") || + strings.HasPrefix(s, "$2b$") || + strings.HasPrefix(s, "$2y$") +} + func (l *LoginReq) Login(ctx context.Context) (map[string]string, error) { logger := util.SharedLogger @@ -71,12 +78,25 @@ func (l *LoginReq) Login(ctx context.Context) (map[string]string, error) { return nil, fmt.Errorf("invalid username/email or password") } - // Verify password using bcrypt - err = bcrypt.CompareHashAndPassword([]byte(storedPasswordHash), []byte(l.Password)) - if err != nil { - // Password doesn't match - logger.Info("Login: invalid password attempt") - return nil, fmt.Errorf("invalid username/email or password") + if isBcryptHash(storedPasswordHash) { + err = bcrypt.CompareHashAndPassword([]byte(storedPasswordHash), []byte(l.Password)) + if err != nil { + logger.Info("Login: invalid password attempt") + return nil, fmt.Errorf("invalid username/email or password") + } + } else { + // Compare plain text for legacy users + if storedPasswordHash != l.Password { + logger.Info("Login: invalid password attempt (legacy)") + return nil, fmt.Errorf("invalid username/email or password") + } + + // Rehash and update DB for this user + newHash, err := bcrypt.GenerateFromPassword([]byte(l.Password), bcrypt.DefaultCost) + if err == nil { + _, _ = db.Exec(ctx, "UPDATE users SET password = $1 WHERE id = $2", string(newHash), id) + logger.Info(fmt.Sprintf("Upgraded password hash for user %v", id)) + } } // Password verified, get user details