refac: password and code hashing & checking go through a domain hasher interface used by the use cases instead of bcrypt in the user repository and the auth handler
This commit is contained in:
1 parent
8460a078e3
commit
ff8cd5f0ec
16 files changed
+725
-88
No files matched your search
@@ -0,0 +1,29 @@
|
||||
package hashing
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/hash"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
const bcryptCost = 12
|
||||
|
||||
type BcryptHasher struct{}
|
||||
|
||||
func NewBcryptHasher() *BcryptHasher {
|
||||
return &BcryptHasher{}
|
||||
}
|
||||
|
||||
func (b *BcryptHasher) Hash(value string) (string, error) {
|
||||
hashed, err := bcrypt.GenerateFromPassword([]byte(value), bcryptCost)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(hashed), nil
|
||||
}
|
||||
|
||||
func (b *BcryptHasher) Compare(hashed string, value string) error {
|
||||
return bcrypt.CompareHashAndPassword([]byte(hashed), []byte(value))
|
||||
}
|
||||
|
||||
var _ hash.Hasher = &BcryptHasher{}
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"RenewCMS/internal/infrastructure/persistence/mappers"
|
||||
entity "RenewCMS/internal/infrastructure/persistence/models"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -28,14 +27,11 @@ func (u *UserRepository) Get(id uint32) (domainUser.User, error) {
|
||||
}
|
||||
|
||||
func (u *UserRepository) Create(user domainUser.User) (domainUser.User, error) {
|
||||
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(user.Password), 12)
|
||||
hashedVerificationCode, _ := bcrypt.GenerateFromPassword([]byte(user.VerificationCode), 12)
|
||||
|
||||
creationResult := u.db.Create(&entity.User{
|
||||
Username: user.Username,
|
||||
Password: string(hashedPassword),
|
||||
Password: user.Password,
|
||||
Email: user.Email,
|
||||
VerificationCode: string(hashedVerificationCode),
|
||||
VerificationCode: user.VerificationCode,
|
||||
VerificationExpiration: user.VerificationExpiration,
|
||||
})
|
||||
if creationResult.Error != nil {
|
||||
@@ -108,8 +104,7 @@ func (u *UserRepository) UpdatePassword(userId uint32, password string) (domainU
|
||||
return domainUser.User{}, err
|
||||
}
|
||||
|
||||
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), 12)
|
||||
localUser.Password = string(hashedPassword)
|
||||
localUser.Password = password
|
||||
err = u.db.Save(&localUser).Error
|
||||
if err != nil {
|
||||
return domainUser.User{}, err
|
||||
@@ -125,8 +120,7 @@ func (u *UserRepository) UpdatePasswordResetCode(userId uint32, code string) (do
|
||||
return domainUser.User{}, err
|
||||
}
|
||||
|
||||
hashedCode, _ := bcrypt.GenerateFromPassword([]byte(code), 12)
|
||||
localUser.PasswordResetCode = string(hashedCode)
|
||||
localUser.PasswordResetCode = code
|
||||
err = u.db.Save(&localUser).Error
|
||||
if err != nil {
|
||||
return domainUser.User{}, err
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/hash"
|
||||
"RenewCMS/internal/domain/user"
|
||||
)
|
||||
|
||||
type AuthenticateUserUseCase struct {
|
||||
userRepository user.Repository
|
||||
hasher hash.Hasher
|
||||
}
|
||||
|
||||
func NewAuthenticateUserUseCase(userRepository user.Repository, hasher hash.Hasher) *AuthenticateUserUseCase {
|
||||
return &AuthenticateUserUseCase{userRepository, hasher}
|
||||
}
|
||||
|
||||
func (a *AuthenticateUserUseCase) Authenticate(username string, password string) (user.User, error) {
|
||||
dbUser, err := a.userRepository.GetByUsername(username)
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
|
||||
if err := a.hasher.Compare(dbUser.Password, password); err != nil {
|
||||
return user.User{}, user.ErrInvalidCredentials
|
||||
}
|
||||
|
||||
return dbUser, nil
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/hash"
|
||||
"RenewCMS/internal/domain/user"
|
||||
"time"
|
||||
|
||||
@@ -9,6 +10,7 @@ import (
|
||||
|
||||
type CreateUserUseCase struct {
|
||||
userRepository user.Repository
|
||||
hasher hash.Hasher
|
||||
}
|
||||
|
||||
type CreateUserCommand struct {
|
||||
@@ -17,20 +19,30 @@ type CreateUserCommand struct {
|
||||
Email string
|
||||
}
|
||||
|
||||
func NewCreateUserUseCase(userRepository user.Repository) *CreateUserUseCase {
|
||||
return &CreateUserUseCase{userRepository}
|
||||
func NewCreateUserUseCase(userRepository user.Repository, hasher hash.Hasher) *CreateUserUseCase {
|
||||
return &CreateUserUseCase{userRepository, hasher}
|
||||
}
|
||||
|
||||
func (g *CreateUserUseCase) CreateUser(createUser CreateUserCommand) (user.User, error) {
|
||||
rawUuid := uuid.NewString()
|
||||
|
||||
hashedPassword, err := g.hasher.Hash(createUser.Password)
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
|
||||
hashedVerificationCode, err := g.hasher.Hash(rawUuid)
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
|
||||
createdUser, err := g.userRepository.Create(user.User{
|
||||
Username: createUser.Username,
|
||||
Password: createUser.Password,
|
||||
Password: hashedPassword,
|
||||
PasswordResetCode: "",
|
||||
Email: createUser.Email,
|
||||
IsVerified: false,
|
||||
VerificationCode: rawUuid,
|
||||
VerificationCode: hashedVerificationCode,
|
||||
VerificationExpiration: time.Now().Add(2 * time.Hour),
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package useCases
|
||||
|
||||
import "RenewCMS/internal/domain/user"
|
||||
import (
|
||||
"RenewCMS/internal/domain/hash"
|
||||
"RenewCMS/internal/domain/user"
|
||||
)
|
||||
|
||||
type UpdateUserUseCase struct {
|
||||
userRepository user.Repository
|
||||
hasher hash.Hasher
|
||||
}
|
||||
|
||||
func NewUpdateUserUseCase(userRepository user.Repository) *UpdateUserUseCase {
|
||||
return &UpdateUserUseCase{userRepository}
|
||||
func NewUpdateUserUseCase(userRepository user.Repository, hasher hash.Hasher) *UpdateUserUseCase {
|
||||
return &UpdateUserUseCase{userRepository, hasher}
|
||||
}
|
||||
|
||||
func (g *UpdateUserUseCase) UpdateVerificationStatus(userId uint32, isVerified bool) (user.User, error) {
|
||||
@@ -15,9 +19,17 @@ func (g *UpdateUserUseCase) UpdateVerificationStatus(userId uint32, isVerified b
|
||||
}
|
||||
|
||||
func (g *UpdateUserUseCase) UpdatePasswordResetCode(userId uint32, code string) (user.User, error) {
|
||||
return g.userRepository.UpdatePasswordResetCode(userId, code)
|
||||
hashedCode, err := g.hasher.Hash(code)
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
return g.userRepository.UpdatePasswordResetCode(userId, hashedCode)
|
||||
}
|
||||
|
||||
func (g *UpdateUserUseCase) UpdatePassword(userId uint32, password string) (user.User, error) {
|
||||
return g.userRepository.UpdatePassword(userId, password)
|
||||
hashedPassword, err := g.hasher.Hash(password)
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
return g.userRepository.UpdatePassword(userId, hashedPassword)
|
||||
}
|
||||
Reference in new issue
Block a user