aboutsummaryrefslogtreecommitdiff
path: root/pkg/service/user/register.go
blob: 69f19a203783a72e161a7d38bfe3e0ca89399244 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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
}