draincloud-core/internal/app/app.go
2024-10-01 01:21:37 +03:00

129 lines
3.0 KiB
Go

package app
import (
"crypto/rand"
"encoding/base64"
"fmt"
"net/http"
"time"
"git.optclblast.xyz/draincloud/draincloud-light/internal/domain"
"git.optclblast.xyz/draincloud/draincloud-light/internal/logger"
"git.optclblast.xyz/draincloud/draincloud-light/internal/storage"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
)
type DrainCloud struct {
mux *gin.Engine
datadase storage.Database
}
func New() *DrainCloud {
mux := gin.Default()
d := new(DrainCloud)
authGroup := mux.Group("/auth")
{
authGroup.POST("/register", d.Register)
authGroup.POST("/login", d.Login)
authGroup.POST("/logout", d.Logout)
}
d.mux = mux
return d
}
func (d *DrainCloud) Register(ctx *gin.Context) {
logger.Debug(ctx, "[register] new request")
req := new(domain.RegisterRequest)
err := ctx.BindJSON(req)
if err != nil {
logger.Error(ctx, "[register] failed to bind request", logger.Err(err))
ctx.JSON(http.StatusBadRequest, map[string]string{
"error": "bad request",
})
return
}
_, err = d.register(ctx, req)
if err != nil {
logger.Error(ctx, "[register] failed to register user", logger.Err(err))
ctx.JSON(http.StatusBadRequest, map[string]string{
"error": err.Error(),
})
return
}
ctx.JSON(http.StatusOK, map[string]bool{
"ok": true,
})
}
type registerResult struct {
cookies []http.Cookie
}
func (d *DrainCloud) register(ctx *gin.Context, req *domain.RegisterRequest) (*registerResult, error) {
if err := validateLoginAndPassword(req.Login, req.Password); err != nil {
return nil, fmt.Errorf("invalid creds: %w", err)
}
_, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10)
if err != nil {
logger.Error(ctx, "[register] failed to generate password", logger.Err(err))
return nil, fmt.Errorf("failed to generate password: %w", err)
}
// _, err = d.datadase.AddUser(ctx, req.Login, req.Login, passwordHash)
// if err != nil {
// return nil, fmt.Errorf("failed to add new user: %w", err)
// }
sessionToken, err := generateSessionToken(50)
if err != nil {
return nil, fmt.Errorf("failed to generate a session token: %w", err)
}
ctx.SetCookie("__Session_token", sessionToken, int((time.Hour * 24).Seconds()), "_path", "_domain", true, true)
csrfToken, err := generateSessionToken(50)
if err != nil {
return nil, fmt.Errorf("failed to generate a csrf token: %w", err)
}
ctx.SetCookie("__Csrf_token", csrfToken, int((time.Hour * 24).Seconds()), "_path", "_domain", true, false)
return &registerResult{}, nil
}
func validateLoginAndPassword(login, password string) error {
if len(login) < 8 {
return fmt.Errorf("login must be longer than 8 chars")
}
if len(password) < 8 {
return fmt.Errorf("password must be longer than 8 chars")
}
return nil
}
func generateSessionToken(length int) (string, error) {
bytes := make([]byte, length)
if _, err := rand.Read(bytes); err != nil {
return "", fmt.Errorf("failed to generate token: %w", err)
}
return base64.URLEncoding.EncodeToString(bytes), nil
}
func (d *DrainCloud) Login(ctx *gin.Context) {
}
func (d *DrainCloud) Logout(ctx *gin.Context) {
}