Initial chaos

This commit is contained in:
2022-09-23 21:37:00 +02:00
parent 510dc87cb3
commit 4f8d553923
22 changed files with 772 additions and 1 deletions

59
pkg/app/app.go Normal file
View 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())
}
}

View 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
View 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})
}

View 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
View 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
View File

@ -0,0 +1,3 @@
package jwt
const SecretKey = "secret"

View 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
View 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
View File

@ -0,0 +1,5 @@
package models
type BaseError struct {
Message string `json:"msg"`
}

16
pkg/models/users.go Normal file
View 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
View File

@ -0,0 +1,5 @@
package models
import "github.com/go-playground/validator/v10"
var Validate = validator.New()