framework/pkg/service/user/register.go

85 lines
1.8 KiB
Go

package user
import (
"context"
"errors"
"regexp"
normalizer "github.com/dimuska139/go-email-normalizer/v3"
"github.com/uptrace/bun/driver/pgdriver"
"golang.org/x/crypto/bcrypt"
"go.neonxp.ru/framework/pkg/model"
"go.neonxp.ru/framework/pkg/tpl"
)
var (
ErrUsernameToShort = errors.New("username_to_short")
ErrUserAlreadyExist = errors.New("user_already_exists")
ErrPasswordTooWeak = errors.New("password_too_weak")
ErrPasswordTooShort = errors.New("password_too_short")
)
const (
minUsernameLen = 3
minPasswordLen = 8
)
func (s *Service) Register(ctx context.Context, form *tpl.RegisterForm) (*model.User, error) {
if len(form.Username) < minUsernameLen {
return nil, ErrUsernameToShort
}
if err := checkPasswordLever(form.Password); err != nil {
return nil, err
}
password, err := bcrypt.GenerateFromPassword([]byte(form.Password), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
n := normalizer.NewNormalizer()
u := &model.User{
Username: form.Username,
Email: n.Normalize(form.Email),
Password: string(password),
}
if _, err := s.db.NewInsert().Model(u).Returning("*").Exec(ctx); err != nil {
pqErr := pgdriver.Error{}
if errors.As(err, &pqErr) {
if pqErr.Field('C') == "23505" {
return nil, ErrUserAlreadyExist
}
}
return nil, err
}
return u, nil
}
func checkPasswordLever(ps string) error {
if len(ps) < minPasswordLen {
return ErrPasswordTooShort
}
lowerCase := `[a-z]{1}`
upperCase := `[A-Z]{1}`
symbol := `[0-9!@#~$%^&*()+|_]{1}`
if b, err := regexp.MatchString(lowerCase, ps); !b || err != nil {
return ErrPasswordTooWeak
}
if b, err := regexp.MatchString(upperCase, ps); !b || err != nil {
return ErrPasswordTooWeak
}
if b, err := regexp.MatchString(symbol, ps); !b || err != nil {
return ErrPasswordTooWeak
}
return nil
}