Skip to content

Commit

Permalink
feat: started to work with sign up
Browse files Browse the repository at this point in the history
  • Loading branch information
SShlykov committed Mar 19, 2024
1 parent 41eaa61 commit 070e4f0
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 96 deletions.
14 changes: 13 additions & 1 deletion auth/docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,19 @@
---
- [x] Модель Пользователя
- [x] Модель токенов
- [ ] Авторизация и Аутентификация
- [ ] Авторизация
- [ ] Регистрация
- [ ] Восстановление пароля
- [ ] Сброс пароля
- [ ] Подтверждение почты
- [ ] Вход
- [ ] Выход
- [ ] Обновление токена
- [ ] Удаление токена
- [ ] Проверка токена
- [ ] Проверка пользователя
- [ ] Проверка роли
- [ ] Проверка прав
---
- [x] Модель прав пользователя
- [ ] Пользовательские права
Expand Down
1 change: 0 additions & 1 deletion auth/internal/domain/adapters/proto_adapters.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ func NullStringToProto(str sql.Null[string]) *wrapperspb.StringValue {
return wrapperspb.String(str.V)
}
return nil

}

func NullDtToProto(dt sql.Null[time.Time]) *timestamppb.Timestamp {
Expand Down
6 changes: 3 additions & 3 deletions auth/internal/domain/adapters/user_proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ func ProtoToUser(protoUser *user_v1.User) *entity.User {
DeletedAt: ProtoToNullDt(protoUser.DeletedAt),
LoggedAt: ProtoToNullDt(protoUser.LoggedAt),
ConfirmedAt: ProtoToNullDt(protoUser.ConfirmedAt),
Login: protoUser.Login,
Email: ProtoToNullString(protoUser.Email),

Login: protoUser.Login,
Email: ProtoToNullString(protoUser.Email),

DeletedBy: ProtoToNullString(protoUser.DeletedBy),
AccessTemplateID: ProtoToNullInt(protoUser.AccessTemplateId),
UpdateAfter: ProtoToNullInt64(protoUser.UpdateAfter),
}

return user

}

func UserToProto(user *entity.User) *user_v1.User {
Expand Down
26 changes: 26 additions & 0 deletions auth/internal/domain/helper/hash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package helper

import (
"golang.org/x/crypto/bcrypt"
)

const (
// PasswordHashCost TODO: перенести в конфиг
PasswordHashCost = 14
)

// HashPassword создает хеш пароля
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), PasswordHashCost)
return string(bytes), err
}

func СomparePasswords(hashedPwd string, plainPwd []byte) bool {
byteHash := []byte(hashedPwd)
err := bcrypt.CompareHashAndPassword(byteHash, plainPwd)
if err != nil {
return false
}

return true
}
36 changes: 36 additions & 0 deletions auth/internal/domain/helper/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package helper

import (
"errors"
"regexp"
)

// ValidateLogin проверяет длину имени пользователя.
func ValidateLogin(username string) error {
if len(username) < 3 || len(username) > 16 {
return errors.New("имя пользователя должно быть от 3 до 16 символов")
}
// TODO: проверка на уникальность
// TODO: Проверка на запрещенные символы или слова
return nil
}

// ValidatePassword проверяет пароль на длину, наличие цифр, заглавных и строчных букв, специальных символов.
func ValidatePassword(password string) error {
if len(password) < 6 || len(password) > 64 {
return errors.New("пароль должен быть от 8 до 64 символов")
}

hasNumber := regexp.MustCompile(`[0-9]+`).MatchString
hasUpper := regexp.MustCompile(`[A-Z]+`).MatchString
hasLower := regexp.MustCompile(`[a-z]+`).MatchString
hasSpecial := regexp.MustCompile(`[!@#$%^&*]+`).MatchString

if !hasNumber(password) || !hasUpper(password) || !hasLower(password) || !hasSpecial(password) {
return errors.New("пароль должен содержать хотя бы одну цифру, одну заглавную и строчную букву, а также один специальный символ")
}

// TODO: игнорировать общеизвестные пароли

return nil
}
42 changes: 36 additions & 6 deletions auth/internal/domain/services/user_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package services

import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/SShlykov/zeitment/auth/internal/domain/adapters"
"github.com/SShlykov/zeitment/auth/internal/domain/helper"
"github.com/SShlykov/zeitment/auth/internal/infrastructure/repository/entity"
"github.com/SShlykov/zeitment/auth/pkg/grpc/user_v1"
"github.com/SShlykov/zeitment/postgres/dbutils"
"google.golang.org/protobuf/types/known/emptypb"
"time"
)

type Repository interface {
Expand All @@ -17,6 +21,7 @@ type Repository interface {
HardDelete(ctx context.Context, id string) error
FindByID(ctx context.Context, id string) (*entity.User, error)
FindByKV(ctx context.Context, options dbutils.QueryOptions) ([]*entity.User, error)
FindByLogin(ctx context.Context, login string) (*entity.User, error)
}

type userServiceServer struct {
Expand All @@ -28,19 +33,39 @@ func NewUserServiceServer(repository Repository) user_v1.UserServiceServer {
return &userServiceServer{repo: repository}
}

func (uss *userServiceServer) Create(ctx context.Context, in *user_v1.CreateUserRequest) (*user_v1.CreateUserResponse, error) {
userId, err := uss.repo.Create(ctx, adapters.ProtoToUser(in.User))
func (uss *userServiceServer) SignUp(ctx context.Context, in *user_v1.SignUpRequest) (*user_v1.SignUpResponse, error) {
if in.User == nil || in.Password == "" {
return nil, errors.New("пользователь или пароль не могут быть пустыми; ошибка протокола")
}
if uss.isUserExist(ctx, in.User.Login) {
return nil, errors.New("пользователь с таким логином уже существует")
}
if err := helper.ValidateLogin(in.User.Login); err != nil {
fmt.Println("Ошибка валидации пароля:", err)
}
hashed, err := helper.HashPassword(in.Password)
if err != nil {
fmt.Println("Ошибка обработки пароля:", err)
}

user := adapters.ProtoToUser(in.User)
user.PasswordHash = hashed
user.UpdateAfter = sql.Null[int64]{Valid: true, V: int64(30 * 24 * time.Hour)}

userID, err := uss.repo.Create(ctx, user)
if err != nil {
return nil, err
}
// TODO: добавить отправку письма с подтверждением регистрации
// TODO: добавить роль по умолчанию
// TODO: вернуть токен

var user *entity.User
user, err = uss.repo.FindByID(ctx, userId)
user, err = uss.repo.FindByID(ctx, userID)
if err != nil {
return nil, errors.New("user not found")
return nil, errors.New("пользователь не найден")
}

return &user_v1.CreateUserResponse{Id: userId, Status: "ok", User: adapters.UserToProto(user)}, nil
return &user_v1.SignUpResponse{Status: "success", Token: "", RoleName: ""}, nil
}

func (uss *userServiceServer) Update(ctx context.Context, in *user_v1.UpdateUserRequest) (*user_v1.UpdateUserResponse, error) {
Expand Down Expand Up @@ -78,3 +103,8 @@ func (uss *userServiceServer) Find(ctx context.Context, in *user_v1.ListUsersReq

return &user_v1.ListUsersResponse{Status: "ok", Users: adapters.UsersToProto(users)}, nil
}

func (uss *userServiceServer) isUserExist(ctx context.Context, login string) bool {
_, err := uss.repo.FindByLogin(ctx, login)
return err == nil
}
1 change: 0 additions & 1 deletion auth/internal/infrastructure/grpc/proto/user_v1.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ service UserService {
//------------------------------------------------------------------------------------------------------------------
// CRUD operations
//------------------------------------------------------------------------------------------------------------------
rpc Create(CreateUserRequest) returns (CreateUserResponse) {};
rpc Update(UpdateUserRequest) returns (UpdateUserResponse) {};
rpc Delete(DeleteUserRequest) returns (google.protobuf.Empty) {};
rpc Get(GetUserRequest) returns (GetUserResponse) {
Expand Down
22 changes: 22 additions & 0 deletions auth/internal/infrastructure/repository/pgrepo/user_repo.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package pgrepo

import (
"context"
"github.com/SShlykov/zeitment/auth/internal/infrastructure/repository/entity"
"github.com/SShlykov/zeitment/postgres"
)

type UsersRepo interface {
Repository[entity.User]
FindByLogin(ctx context.Context, login string) (*entity.User, error)
}

type usersRepo struct {
Expand All @@ -22,3 +24,23 @@ func NewUsersRepository(db postgres.Client) UsersRepo {
},
}
}

func (ur *usersRepo) FindByLogin(ctx context.Context, login string) (*entity.User, error) {
query, args, err := ur.db.Builder().
Select("*").
From(ur.entity.TableName()).
Where("login = ?", login).
ToSql()
if err != nil {
return nil, err
}

q := postgres.Query{Name: ur.repository.Name + ".FindByLogin", Raw: query}

row := ur.db.DB().QueryRowContext(ctx, q, args...)

var user entity.User
user, err = ur.entity.ReadItem(row)

return &user, err
}
85 changes: 39 additions & 46 deletions auth/pkg/grpc/user_v1/user_v1.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion auth/pkg/grpc/user_v1/user_v1.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 070e4f0

Please sign in to comment.