70 lines
1.5 KiB
Go
70 lines
1.5 KiB
Go
package password
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"unicode/utf8"
|
||
|
|
|
||
|
|
"cmroubao/backend-api/internal/domain"
|
||
|
|
|
||
|
|
"golang.org/x/crypto/bcrypt"
|
||
|
|
)
|
||
|
|
|
||
|
|
var (
|
||
|
|
ErrInvalidPassword = errors.New("password is invalid")
|
||
|
|
ErrPasswordMismatch = errors.New("password does not match")
|
||
|
|
)
|
||
|
|
|
||
|
|
type Bcrypt struct {
|
||
|
|
cost int
|
||
|
|
dummyHash string
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewBcrypt(cost int) (*Bcrypt, error) {
|
||
|
|
if cost < bcrypt.MinCost || cost > bcrypt.MaxCost {
|
||
|
|
return nil, errors.New("bcrypt cost is out of range")
|
||
|
|
}
|
||
|
|
dummyHash, err := bcrypt.GenerateFromPassword(
|
||
|
|
[]byte("cmroubao-dummy-password"),
|
||
|
|
cost,
|
||
|
|
)
|
||
|
|
if err != nil {
|
||
|
|
return nil, errors.New("initialize bcrypt dummy hash")
|
||
|
|
}
|
||
|
|
return &Bcrypt{cost: cost, dummyHash: string(dummyHash)}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (manager *Bcrypt) Hash(plain string) (string, error) {
|
||
|
|
if !utf8.ValidString(plain) ||
|
||
|
|
len([]byte(plain)) < domain.MinPasswordBytes ||
|
||
|
|
len([]byte(plain)) > domain.MaxPasswordBytes {
|
||
|
|
return "", ErrInvalidPassword
|
||
|
|
}
|
||
|
|
value, err := bcrypt.GenerateFromPassword([]byte(plain), manager.cost)
|
||
|
|
if err != nil {
|
||
|
|
return "", errors.New("hash password")
|
||
|
|
}
|
||
|
|
return string(value), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (manager *Bcrypt) VerifyDummy(plain string) {
|
||
|
|
_ = bcrypt.CompareHashAndPassword(
|
||
|
|
[]byte(manager.dummyHash),
|
||
|
|
[]byte(plain),
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (manager *Bcrypt) Verify(encoded string, plain string) error {
|
||
|
|
if encoded == "" ||
|
||
|
|
plain == "" ||
|
||
|
|
len([]byte(plain)) > domain.MaxPasswordBytes {
|
||
|
|
return ErrPasswordMismatch
|
||
|
|
}
|
||
|
|
if err := bcrypt.CompareHashAndPassword(
|
||
|
|
[]byte(encoded),
|
||
|
|
[]byte(plain),
|
||
|
|
); err != nil {
|
||
|
|
return ErrPasswordMismatch
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|