Skip to content

Commit

Permalink
auth & reg
Browse files Browse the repository at this point in the history
  • Loading branch information
pieceowater committed Dec 2, 2024
1 parent 086317c commit defe7de
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 61 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ go 1.23.0
require (
ariga.io/atlas-provider-gorm v0.5.0
github.com/gin-gonic/gin v1.10.0
github.com/golang-jwt/jwt/v4 v4.5.1
github.com/golang-jwt/jwt/v5 v5.2.0
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
github.com/pieceowater-dev/lotof.hub.proto v0.0.24
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
Expand Down Expand Up @@ -122,10 +124,6 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pieceowater-dev/lotof.hub.proto v0.0.22 h1:jGDLAACixTVetj08UvT6GQszKyw1P8OL9w95qBwmWNQ=
github.com/pieceowater-dev/lotof.hub.proto v0.0.22/go.mod h1:9uwfvIUGGzTrTIVzQ4gH8hmrRC8sgtnLUhyPN5swIME=
github.com/pieceowater-dev/lotof.hub.proto v0.0.23 h1:J4sqptho83k6EcJ7AkdWbkE4MnUYKKYHoIN5GENcvIs=
github.com/pieceowater-dev/lotof.hub.proto v0.0.23/go.mod h1:9uwfvIUGGzTrTIVzQ4gH8hmrRC8sgtnLUhyPN5swIME=
github.com/pieceowater-dev/lotof.hub.proto v0.0.24 h1:ULHeaE5zOaulaSfgbl+U1wYat+PGYiNayJZpYnxuaC8=
github.com/pieceowater-dev/lotof.hub.proto v0.0.24/go.mod h1:9uwfvIUGGzTrTIVzQ4gH8hmrRC8sgtnLUhyPN5swIME=
github.com/pieceowater-dev/lotof.lib.gossiper/v2 v2.0.6 h1:5WEnZAd/hwMDAL8sVUoL+zO4wWeQetVO4Zo+NgxzC80=
Expand Down
14 changes: 10 additions & 4 deletions internal/core/cfg/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import (
)

type Config struct {
GrpcPort string
RestPort string
GrpcPort string
RestPort string

PostgresDatabaseDSN string
PostgresModels []any

SecretKey string
}

var (
Expand All @@ -29,15 +32,18 @@ func Inst() *Config {
}

instance = &Config{
GrpcPort: getEnv("GRPC_PORT", "50051"),
RestPort: getEnv("REST_PORT", "3000"),
GrpcPort: getEnv("GRPC_PORT", "50051"),
RestPort: getEnv("REST_PORT", "3000"),

PostgresDatabaseDSN: getEnv("POSTGRES_DB_DSN", "postgres://pieceouser:pieceopassword@localhost:5432/users?sslmode=disable"),
PostgresModels: []any{
// models to migration here:
// &ent.MyModel{},
&user.User{},
&frinedship.Friendship{},
},

SecretKey: getEnv("SECRET_KEY", "secret"),
}
})
return instance
Expand Down
1 change: 1 addition & 0 deletions internal/pkg/auth/auth.module.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func New() *Module {
gossiper.PostgresDB,
cfg.Inst().PostgresDatabaseDSN,
false,
[]any{},
)
if err != nil {
log.Fatalf("Failed to create database instance: %v", err)
Expand Down
44 changes: 42 additions & 2 deletions internal/pkg/auth/ctrl/auth.ctrl.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package ctrl

import "app/internal/pkg/auth/svc"
import (
pb "app/internal/core/grpc/generated"
"app/internal/pkg/auth/svc"
"app/internal/pkg/user/ent"
"context"
)

type AuthController struct {
authService *svc.AuthService
pb.UnimplementedAuthServiceServer
}

func NewAuthController(service *svc.AuthService) *AuthController {
Expand All @@ -12,4 +18,38 @@ func NewAuthController(service *svc.AuthService) *AuthController {
}
}

// todo: implement methods
func (a AuthController) Login(_ context.Context, request *pb.LoginRequest) (*pb.AuthResponse, error) {
token, user, err := a.authService.Login(request.Email, request.Password)
if err != nil {
return nil, err
}

return &pb.AuthResponse{
Token: *token,
User: &pb.User{
Id: user.ID.String(),
Username: user.Username,
Email: user.Email,
},
}, nil
}

func (a AuthController) Register(_ context.Context, request *pb.RegisterRequest) (*pb.AuthResponse, error) {
token, user, err := a.authService.Register(&ent.User{
Username: request.Username,
Email: request.Email,
Password: request.Password,
})
if err != nil {
return nil, err
}

return &pb.AuthResponse{
Token: *token,
User: &pb.User{
Id: user.ID.String(),
Username: user.Username,
Email: user.Email,
},
}, nil
}
62 changes: 50 additions & 12 deletions internal/pkg/auth/svc/auth.svc.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package svc

import (
"app/internal/core/cfg"
"app/internal/pkg/user/ent"
"context"
"errors"
"fmt"
"github.com/golang-jwt/jwt/v5"
gossiper "github.com/pieceowater-dev/lotof.lib.gossiper/v2"
"golang.org/x/crypto/bcrypt"
"time"
Expand All @@ -17,33 +19,69 @@ func NewAuthService(db gossiper.Database) *AuthService {
return &AuthService{db: db}
}

func (s *AuthService) Login(ctx context.Context, email, password string) (*ent.User, error) {
// Generate JWT Token
func (s *AuthService) generateJWT(user *ent.User) (*string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"userId": user.ID.String(),
"email": user.Email,
"exp": time.Now().Add(168 * time.Hour).Unix(),
})

secret := cfg.Inst().SecretKey
tokenString, err := token.SignedString([]byte(secret))
if err != nil {
return nil, fmt.Errorf("failed to generate token: %w", err)
}

return &tokenString, nil
}

func (s *AuthService) Login(email, password string) (*string, *ent.User, error) {
var user ent.User
if err := s.db.GetDB().Where("email = ? AND deleted = ?", email, false).First(&user).Error; err != nil {
return nil, errors.New("incorrect user or password")

if err := s.db.GetDB().Where("email = ? AND deleted_at IS NULL", email).First(&user).Error; err != nil {
return nil, nil, errors.New("invalid email or password")
}

// Compare hashed password
// Check user state todo: implement this logic later
//if user.State != ent.Active {
// return nil, nil, errors.New("account is not active")
//}

// Validate password
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
return nil, errors.New("incorrect user or password")
return nil, nil, errors.New("invalid email or password")
}

// Generate JWT token
token, err := s.generateJWT(&user)
if err != nil {
return nil, nil, err
}

return &user, nil
return token, &user, nil
}

func (s *AuthService) Register(ctx context.Context, user *ent.User) (*ent.User, error) {
// Hash the password before saving
func (s *AuthService) Register(user *ent.User) (*string, *ent.User, error) {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
return nil, err
return nil, nil, err
}

user.Password = string(hashedPassword)
user.CreatedAt = time.Now()
user.State = ent.Suspended

// Save user to DB
if err := s.db.GetDB().Create(user).Error; err != nil {
return nil, err
return nil, nil, err
}

// Generate JWT token
token, err := s.generateJWT(user)
if err != nil {
return nil, nil, err
}

return user, nil
return token, user, nil
}
10 changes: 6 additions & 4 deletions internal/pkg/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@ package pkg

import (
pb "app/internal/core/grpc/generated"
"app/internal/pkg/auth"
"app/internal/pkg/friendship"
"app/internal/pkg/user"
"github.com/gin-gonic/gin"
"google.golang.org/grpc"
)

type Router struct {
userModule *user.Module
//authModule *auth.Module
userModule *user.Module
authModule *auth.Module
friendshipModule *friendship.Module
}

func NewRouter() *Router {
return &Router{
userModule: user.New(),
//authModule: auth.New(),
userModule: user.New(),
authModule: auth.New(),
friendshipModule: friendship.New(),
}
}
Expand All @@ -26,6 +27,7 @@ func NewRouter() *Router {
func (r *Router) InitGRPC(grpcServer *grpc.Server) {
// Register gRPC services
pb.RegisterUserServiceServer(grpcServer, r.userModule.Controller)
pb.RegisterAuthServiceServer(grpcServer, r.authModule.Controller)
pb.RegisterFriendshipServiceServer(grpcServer, r.friendshipModule.Controller)
}

Expand Down
25 changes: 2 additions & 23 deletions internal/pkg/user/ent/user.ent.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package ent

import (
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)

Expand All @@ -24,30 +23,10 @@ type User struct {
Friends []*User `gorm:"many2many:friendships;joinForeignKey:UserID;joinReferences:FriendID"`
}

// BeforeCreate Hook for generating custom UUID and password hashing
// BeforeCreate Hook for generating custom UUID
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
// Generate custom UUID for user
u.ID = uuid.New()

// Hash password if it's not empty
if u.Password != "" {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
if err != nil {
return err
}
u.Password = string(hashedPassword)
}
return nil
}

// BeforeSave Hook for updating timestamp and hashing password (if necessary)
func (u *User) BeforeSave(tx *gorm.DB) (err error) {
if u.Password != "" {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
if err != nil {
return err
}
u.Password = string(hashedPassword)
}
//todo: generate hashed password here ONLY
return nil
}
19 changes: 7 additions & 12 deletions internal/pkg/user/svc/user.svc.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
gossiper "github.com/pieceowater-dev/lotof.lib.gossiper/v2"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)

Expand All @@ -17,7 +18,12 @@ func NewUserService(db gossiper.Database) *UserService {
return &UserService{db: db}
}

func (s *UserService) CreateUser(user *ent.User) (*ent.User, error) {
func (s *UserService) CreateUser(user *ent.User) (*ent.User, error) { // todo: delete this later
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
user.Password = string(hashedPassword)
if err := s.db.GetDB().Create(user).Error; err != nil {
if errors.Is(err, gorm.ErrDuplicatedKey) {
return nil, errors.New("email already exists")
Expand Down Expand Up @@ -85,14 +91,3 @@ func (s *UserService) GetUsers(filter gossiper.Filter[string]) (gossiper.Paginat
// Create paginated result
return gossiper.NewPaginatedResult(grpcUsers, int(count)), nil
}

//func (s *UserService) AddFriend(userID, friendID string) error {
// var user, friend ent.User
// if err := s.db.GetDB().First(&user, "id = ?", userID).Error; err != nil {
// return err
// }
// if err := s.db.GetDB().First(&friend, "id = ?", friendID).Error; err != nil {
// return err
// }
// return s.db.GetDB().Model(&user).Association("Friends").Append(&friend)
//}

0 comments on commit defe7de

Please sign in to comment.