129 lines
3.0 KiB
Go
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 ®isterResult{}, 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) {
|
|
|
|
}
|