diff --git a/controllers/cartItemController.go b/controllers/cartItemController.go index f21632a..8b333ba 100644 --- a/controllers/cartItemController.go +++ b/controllers/cartItemController.go @@ -1,8 +1,6 @@ package controllers import ( - "crypto/rand" - "encoding/hex" "errors" "fmt" "net/http" @@ -15,6 +13,7 @@ import ( "git.dynamicdiscord.de/kalipso/zineshop/models" //"git.dynamicdiscord.de/kalipso/zineshop/services" "git.dynamicdiscord.de/kalipso/zineshop/repositories" + "git.dynamicdiscord.de/kalipso/zineshop/utils" ) type CartItemController interface { @@ -53,15 +52,6 @@ func getSetCookieValue(c *gin.Context, cookieName string) string { return "" // Return empty string if cookie is not found } -func generateSessionId(length int) string { - bytes := make([]byte, length) // 16 bytes = 128 bits - _, err := rand.Read(bytes) - if err != nil { - panic("failed to generate session ID") - } - return hex.EncodeToString(bytes) -} - func GetSessionId(ctx *gin.Context) string { sessionId, err := ctx.Cookie("session_id") @@ -73,17 +63,13 @@ func GetSessionId(ctx *gin.Context) string { return responseCookie } - sessionId = generateSessionId(16) + sessionId = utils.GenerateSessionId(16) ctx.SetCookie("session_id", sessionId, 3600, "/", "", false, true) } return sessionId } -func GenerateToken() string { - return generateSessionId(16) -} - func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.CartItem, error) { sessionId := GetSessionId(ctx) shopItemIdStr := ctx.PostForm("ShopItemId") @@ -162,7 +148,7 @@ func (rc *cartItemController) NewAddressFromForm(ctx *gin.Context) (models.Addre func (rc *cartItemController) NewOrderFromForm(ctx *gin.Context) (models.Order, error) { sessionId := GetSessionId(ctx) status := models.OrderStatus("AwaitingConfirmation") - token := GenerateToken() + token := utils.GenerateToken() email := ctx.PostForm("email") comment := ctx.PostForm("comment") firstName := ctx.PostForm("firstName") diff --git a/controllers/userController.go b/controllers/userController.go index f20a581..ba31b35 100644 --- a/controllers/userController.go +++ b/controllers/userController.go @@ -35,7 +35,7 @@ func (uc *UserController) Register(c *gin.Context) { return } - _, err = services.Users.Register(body.Name, body.Email, body.Password) + _, err = services.Users.Register(body.Name, body.Email, body.Password, false) if err != nil { fmt.Println("Error: ", err) @@ -152,18 +152,75 @@ func (rc *UserController) RegisterHandler(c *gin.Context) { email := c.PostForm("email") password := c.PostForm("password") - _, err := services.Users.Register(name, email, password) + //first registered user is admin + isEmpty, _ := repositories.Users.IsEmpty() + if isEmpty { + _, err := services.Users.Register(name, email, password, true) + if err != nil { + data := gin.H{ + "error": "Registering Failed.", + "success": "", + } + c.HTML(http.StatusOK, "register.html", data) + return + } + data := gin.H{ + "error": "", + "success": "You successfully registered as Admin. Try logging in.", + } + + c.HTML(http.StatusOK, "register.html", data) + return + } + + //for any other user token is required + token := c.PostForm("token") + + if token == "" { + data := gin.H{ + "error": "No token. No register.", + "success": "", + } + + c.HTML(http.StatusOK, "register.html", data) + } + + tokenExists, err := repositories.Tokens.Exists(token) + + if err != nil { + data := gin.H{ + "error": err, + "success": "", + } + + c.HTML(http.StatusOK, "register.html", data) + } + + if !tokenExists { + data := gin.H{ + "error": "Invalid Token.", + "success": "", + } + c.HTML(http.StatusOK, "register.html", data) + } + + _, err = services.Users.Register(name, email, password, false) if err != nil { data := gin.H{ "error": "Registering Failed.", "success": "", } - c.HTML(http.StatusOK, "register.html", data) return } + err = repositories.Tokens.Delete(token) + + if err != nil { + fmt.Println("Could not delete RegisterToken: ", err) + } + data := gin.H{ "error": "", "success": "You successfully registered. Try logging in.", diff --git a/models/user.go b/models/user.go index 4b16094..b646fdc 100644 --- a/models/user.go +++ b/models/user.go @@ -4,9 +4,15 @@ import ( "gorm.io/gorm" ) +type RegisterToken struct { + gorm.Model + Token string `json:"token" binding:"required" gorm:"unique;not null"` +} + type User struct { gorm.Model - Name string `json:"name" binding:"required" gorm:"unique;not null"` + Name string `json:"name" binding:"required" gorm:"unique;not null"` Password string `json:"password" binding:"required" gorm:"not null"` - Email string `json:"email" binding:"required,email" gorm:"unique;not null"` + Email string `json:"email" binding:"required,email" gorm:"unique;not null"` + IsAdmin bool `json:"isAdmin" gorm:"default:false;not null"` } diff --git a/repositories/registerTokenRepository.go b/repositories/registerTokenRepository.go new file mode 100644 index 0000000..8d8d1d4 --- /dev/null +++ b/repositories/registerTokenRepository.go @@ -0,0 +1,81 @@ +package repositories + +import ( + "fmt" + + "gorm.io/gorm" + + "git.dynamicdiscord.de/kalipso/zineshop/models" + "git.dynamicdiscord.de/kalipso/zineshop/utils" +) + +type RegisterTokenRepository interface { + Create() (models.RegisterToken, error) + GetAll() ([]models.RegisterToken, error) + Exists(string) (bool, error) + Delete(string) error +} + +type GORMRegisterTokenRepository struct { + DB *gorm.DB +} + +func NewGORMRegisterTokenRepository(db *gorm.DB) RegisterTokenRepository { + return &GORMRegisterTokenRepository{ + DB: db, + } +} + +func (t *GORMRegisterTokenRepository) Create() (models.RegisterToken, error) { + token := utils.GenerateToken() + + exists, err := t.Exists(token) + if err != nil { + return models.RegisterToken{}, err + } + + if exists { + return t.Create() + } + + newToken := models.RegisterToken{ + Token: token, + } + result := t.DB.Create(&newToken) + + if result.Error != nil { + return models.RegisterToken{}, result.Error + } + + return newToken, nil +} + +func (t *GORMRegisterTokenRepository) GetAll() ([]models.RegisterToken, error) { + var tokens []models.RegisterToken + result := t.DB.Find(&tokens) + + return tokens, result.Error +} + +func (t *GORMRegisterTokenRepository) Exists(tokenString string) (bool, error) { + var token models.RegisterToken + result := t.DB.First(&token, tokenString) + + if result.Error != nil { + return false, result.Error + } + + return true, nil +} + +func (t *GORMRegisterTokenRepository) Delete(token string) error { + result := t.DB.Where("token = ?", token).Delete(&models.RegisterToken{}) + + if result.Error != nil { + return result.Error + } else if result.RowsAffected == 0 { + return fmt.Errorf("Token not found, could not be deleted") + } + + return nil +} diff --git a/repositories/repository.go b/repositories/repository.go index 33f60ae..e3e81ff 100644 --- a/repositories/repository.go +++ b/repositories/repository.go @@ -14,6 +14,7 @@ var ( Tags TagRepository CartItems CartItemRepository Orders OrderRepository + Tokens RegisterTokenRepository ) func InitRepositories() { @@ -27,7 +28,8 @@ func InitRepositories() { &models.User{}, &models.Tag{}, &models.CartItem{}, - &models.Order{}) + &models.Order{}, + &models.RegisterToken{}) if err != nil { panic("failed to migrate database") @@ -38,4 +40,5 @@ func InitRepositories() { Tags = NewGORMTagRepository(db) CartItems = NewGORMCartItemRepository(db) Orders = NewGORMOrderRepository(db) + Tokens = NewGORMRegisterTokenRepository(db) } diff --git a/services/userService.go b/services/userService.go index 597c5f6..3f4e551 100644 --- a/services/userService.go +++ b/services/userService.go @@ -1,9 +1,9 @@ package services -import( +import ( + "golang.org/x/crypto/bcrypt" "os" "time" - "golang.org/x/crypto/bcrypt" "github.com/golang-jwt/jwt/v5" @@ -11,13 +11,13 @@ import( "git.dynamicdiscord.de/kalipso/zineshop/repositories" ) -var( +var ( Users UserService = UserService{} ) -type UserService struct {} +type UserService struct{} -func (u *UserService) Register(name string, email string, password string) (models.User, error) { +func (u *UserService) Register(name string, email string, password string, isAdmin bool) (models.User, error) { //hash pw hash, err := bcrypt.GenerateFromPassword([]byte(password), 10) @@ -25,7 +25,7 @@ func (u *UserService) Register(name string, email string, password string) (mode return models.User{}, err } - user := models.User{Name: name, Email: email, Password: string(hash)} + user := models.User{Name: name, Email: email, Password: string(hash), IsAdmin: isAdmin} _, err = repositories.Users.Create(user) if err != nil { @@ -35,7 +35,7 @@ func (u *UserService) Register(name string, email string, password string) (mode return user, nil } -//return jwt tokenstring on success +// return jwt tokenstring on success func (u *UserService) Login(email string, password string) (string, error) { //lookup requested user user, err := repositories.Users.GetByEmail(email)