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 }