Initial chaos
This commit is contained in:
59
pkg/app/app.go
Normal file
59
pkg/app/app.go
Normal file
@ -0,0 +1,59 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"twitch-clone/pkg/database"
|
||||
"twitch-clone/pkg/handler"
|
||||
"twitch-clone/pkg/middleware"
|
||||
"twitch-clone/pkg/models"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
)
|
||||
|
||||
/*Init : set the port,cors,api and then serve the api*/
|
||||
func Init() {
|
||||
app := fiber.New(fiber.Config{
|
||||
ErrorHandler: func(ctx *fiber.Ctx, err error) error {
|
||||
code := fiber.StatusInternalServerError
|
||||
if e, ok := err.(*fiber.Error); ok {
|
||||
code = e.Code
|
||||
}
|
||||
|
||||
return ctx.Status(code).JSON(models.BaseError{Message: err.Error()})
|
||||
},
|
||||
})
|
||||
database.ConnectDb()
|
||||
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowOrigins: "*",
|
||||
AllowMethods: "GET, POST, HEAD, PUT,DELETE, PATCH, OPTIONS",
|
||||
AllowCredentials: true,
|
||||
}))
|
||||
app.Use(logger.New())
|
||||
|
||||
api := app.Group("/api")
|
||||
v1 := api.Group("/v1")
|
||||
|
||||
auth := v1.Group("/auth")
|
||||
auth.Post("login", handler.Login)
|
||||
auth.Post("register", handler.Register)
|
||||
|
||||
test := v1.Group("/test", middleware.CheckToken)
|
||||
test.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("This is a protected route!")
|
||||
})
|
||||
|
||||
// Serve SPA
|
||||
app.Static("/", "./dist")
|
||||
app.Get("/*", func(ctx *fiber.Ctx) error {
|
||||
return ctx.SendFile("./dist/index.html")
|
||||
})
|
||||
|
||||
err := app.Listen(":5000")
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
54
pkg/database/connection.go
Normal file
54
pkg/database/connection.go
Normal file
@ -0,0 +1,54 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"twitch-clone/pkg/models"
|
||||
|
||||
"github.com/bwmarrin/snowflake"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
type Dbinstance struct {
|
||||
Db *gorm.DB
|
||||
Snowflake *snowflake.Node
|
||||
}
|
||||
|
||||
var DB Dbinstance
|
||||
|
||||
// connectDb
|
||||
func ConnectDb() {
|
||||
node, err := snowflake.NewNode(1)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to setup snowflake generator. \n", err)
|
||||
}
|
||||
|
||||
dsn := "host=postgres user=postgres password=postgres dbname=postgres port=5432 sslmode=disable"
|
||||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Info),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("Failed to connect to database. \n", err)
|
||||
}
|
||||
|
||||
log.Println("connected")
|
||||
db.Logger = logger.Default.LogMode(logger.Info)
|
||||
|
||||
db.AutoMigrate(&models.User{})
|
||||
|
||||
DB = Dbinstance{
|
||||
Db: db,
|
||||
Snowflake: node,
|
||||
}
|
||||
}
|
||||
|
||||
func Db() *gorm.DB {
|
||||
return DB.Db
|
||||
}
|
||||
|
||||
func GetID() int64 {
|
||||
return DB.Snowflake.Generate().Int64()
|
||||
}
|
46
pkg/handler/userLogin.go
Normal file
46
pkg/handler/userLogin.go
Normal file
@ -0,0 +1,46 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"twitch-clone/pkg/database"
|
||||
"twitch-clone/pkg/jwt"
|
||||
"twitch-clone/pkg/models"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type LoginRequest struct {
|
||||
Username string `json:"username" validate:"required,min=4,max=32"`
|
||||
Password string `json:"password" validate:"required,min=8,max=128"`
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
Token string `json:"access_token"`
|
||||
}
|
||||
|
||||
func Login(ctx *fiber.Ctx) error {
|
||||
db := database.Db()
|
||||
body := LoginRequest{}
|
||||
|
||||
if err := ctx.BodyParser(&body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := models.Validate.Struct(body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user := new(models.User)
|
||||
result := db.Where(&models.User{Username: body.Username, Password: body.Password}).Select("id").First(user)
|
||||
|
||||
if result.Error != nil {
|
||||
return errors.New("invalid combination of username and password")
|
||||
}
|
||||
|
||||
token, err := jwt.GenerateJWT(models.Claim{ID: user.ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ctx.JSON(LoginResponse{Token: token})
|
||||
}
|
45
pkg/handler/userRegister.go
Normal file
45
pkg/handler/userRegister.go
Normal file
@ -0,0 +1,45 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"twitch-clone/pkg/database"
|
||||
"twitch-clone/pkg/jwt"
|
||||
"twitch-clone/pkg/models"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type RegisterRequest struct {
|
||||
Email string `json:"email" validate:"required,email"`
|
||||
Username string `json:"username" validate:"required,min=4,max=32"`
|
||||
Password string `json:"password" validate:"required,min=8,max=128"`
|
||||
}
|
||||
|
||||
type RegisterResponse struct {
|
||||
Token string `json:"access_token"`
|
||||
}
|
||||
|
||||
func Register(ctx *fiber.Ctx) error {
|
||||
db := database.Db()
|
||||
body := RegisterRequest{}
|
||||
|
||||
if err := ctx.BodyParser(&body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := models.Validate.Struct(body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user := models.User{ID: database.GetID(), Username: body.Username, Password: body.Password, Email: body.Email}
|
||||
result := db.Create(&user)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
token, err := jwt.GenerateJWT(models.Claim{ID: user.ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ctx.JSON(LoginResponse{Token: token})
|
||||
}
|
51
pkg/jwt/jwt.go
Normal file
51
pkg/jwt/jwt.go
Normal file
@ -0,0 +1,51 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"twitch-clone/pkg/models"
|
||||
|
||||
jwt "github.com/golang-jwt/jwt"
|
||||
)
|
||||
|
||||
func GenerateJWT(user models.Claim) (string, error) {
|
||||
payload := jwt.MapClaims{
|
||||
"id": user.ID,
|
||||
"exp": time.Now().Add(time.Hour * 1500).Unix(),
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, payload)
|
||||
tokenStr, err := token.SignedString([]byte(SecretKey))
|
||||
|
||||
if err != nil {
|
||||
return tokenStr, err
|
||||
}
|
||||
return tokenStr, nil
|
||||
}
|
||||
|
||||
func ProcessJWT(token string) (*models.Claim, bool, int64, error) {
|
||||
claims := &models.Claim{}
|
||||
|
||||
splitToken := strings.Split(token, "Bearer")
|
||||
|
||||
if len(splitToken) != 2 {
|
||||
return claims, false, 0, errors.New("invalid JWT format")
|
||||
}
|
||||
|
||||
token = strings.TrimSpace(splitToken[1])
|
||||
tkn, err := jwt.ParseWithClaims(token, claims, func(tk *jwt.Token) (interface{}, error) {
|
||||
return []byte(SecretKey), nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return claims, false, 0, err
|
||||
}
|
||||
|
||||
if !tkn.Valid {
|
||||
return claims, false, 0, errors.New("invalid JWT token")
|
||||
}
|
||||
|
||||
// TODO: validate whether user exists
|
||||
return claims, true, claims.ID, nil
|
||||
}
|
3
pkg/jwt/secret.go
Normal file
3
pkg/jwt/secret.go
Normal file
@ -0,0 +1,3 @@
|
||||
package jwt
|
||||
|
||||
const SecretKey = "secret"
|
18
pkg/middleware/checkToken.go
Normal file
18
pkg/middleware/checkToken.go
Normal file
@ -0,0 +1,18 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"twitch-clone/pkg/jwt"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
/*CheckToken : Check the validate of the jwt*/
|
||||
func CheckToken(c *fiber.Ctx) error {
|
||||
_, _, _, err := jwt.ProcessJWT(c.Get("Authorization"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Next()
|
||||
return nil
|
||||
}
|
11
pkg/models/claim.go
Normal file
11
pkg/models/claim.go
Normal file
@ -0,0 +1,11 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
type Claim struct {
|
||||
ID int64 `json:"id,omitempty"`
|
||||
|
||||
jwt.StandardClaims
|
||||
}
|
5
pkg/models/errors.go
Normal file
5
pkg/models/errors.go
Normal file
@ -0,0 +1,5 @@
|
||||
package models
|
||||
|
||||
type BaseError struct {
|
||||
Message string `json:"msg"`
|
||||
}
|
16
pkg/models/users.go
Normal file
16
pkg/models/users.go
Normal file
@ -0,0 +1,16 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int64 `json:"id,omitempty" gorm:"primaryKey"`
|
||||
Username string `json:"name,omitempty" gorm:"unique"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
5
pkg/models/validator.go
Normal file
5
pkg/models/validator.go
Normal file
@ -0,0 +1,5 @@
|
||||
package models
|
||||
|
||||
import "github.com/go-playground/validator/v10"
|
||||
|
||||
var Validate = validator.New()
|
Reference in New Issue
Block a user