Hermes/internal/core/utils/password.go

77 lines
1.7 KiB
Go

package utils
import (
"fmt"
"backend/pkg/charsets"
"golang.org/x/crypto/bcrypt"
)
type PasswordUtil interface {
Hash(password string) (string, error)
Compare(password, hash string) bool
Validate(password string) error
}
func NewPasswordUtil() PasswordUtil {
specialChars := `!@#$%^&*()_-+={[}]|\:;"'<,>.?/`
return &passwordUtil{
charsetSpecialChars: charsets.NewCharsetFromString(specialChars),
}
}
type passwordUtil struct {
charsetSpecialChars charsets.Charset
}
func (b *passwordUtil) Hash(password string) (string, error) {
bytes, _ := bcrypt.GenerateFromPassword([]byte(password), 8) //bcrypt.DefaultCost)
return string(bytes), nil
}
func (b *passwordUtil) Compare(password, hash string) bool {
return nil == bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
}
func (b *passwordUtil) Validate(password string) error {
if len(password) < 8 {
return fmt.Errorf("password must contain 8 or more characters")
}
charsetUpper := charsets.GetCharset(charsets.CharsetTypeLettersUpper)
charsetLower := charsets.GetCharset(charsets.CharsetTypeLettersLower)
lowercaseLettersCount := 0
uppercaseLettersCount := 0
specialCharsCount := 0
for _, v := range password {
if b.charsetSpecialChars.TestRune(v) {
specialCharsCount++
continue
}
if charsetUpper.TestRune(v) {
uppercaseLettersCount++
continue
}
if charsetLower.TestRune(v) {
lowercaseLettersCount++
continue
}
}
if lowercaseLettersCount == 0 {
return fmt.Errorf("password must contain at least 1 lowercase letter")
}
if uppercaseLettersCount == 0 {
return fmt.Errorf("password must contain at least 1 uppercase letter")
}
if specialCharsCount == 0 {
return fmt.Errorf("password must contain at least 1 special character")
}
return nil
}