122 lines
3.3 KiB
Go
122 lines
3.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.optclblast.xyz/draincloud/draincloud-core/internal/common"
|
|
"git.optclblast.xyz/draincloud/draincloud-core/internal/domain"
|
|
"git.optclblast.xyz/draincloud/draincloud-core/internal/handler"
|
|
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
|
|
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage"
|
|
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models"
|
|
"github.com/google/uuid"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type RegisterHandler struct {
|
|
*handler.BaseHandler
|
|
authStorage storage.AuthStorage
|
|
}
|
|
|
|
func NewRegisterHandler(
|
|
authStorage storage.AuthStorage,
|
|
) *RegisterHandler {
|
|
h := &RegisterHandler{
|
|
authStorage: authStorage,
|
|
BaseHandler: handler.New().
|
|
WithName("registerv1").
|
|
WithRequiredResolveParams(),
|
|
}
|
|
h.WithProcessFunc(h.process)
|
|
return h
|
|
}
|
|
|
|
func (h *RegisterHandler) process(ctx context.Context, req *common.Request, w handler.Writer) error {
|
|
regReq := new(domain.RegisterRequest)
|
|
|
|
if err := json.Unmarshal(req.Body, regReq); err != nil {
|
|
return err
|
|
}
|
|
|
|
resp, err := h.register(ctx, regReq, w)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to register user: %w", err)
|
|
}
|
|
|
|
w.Write(ctx, resp)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *RegisterHandler) register(
|
|
ctx context.Context,
|
|
req *domain.RegisterRequest,
|
|
w handler.Writer,
|
|
) (*domain.RegisterResponse, error) {
|
|
if err := validateLoginAndPassword(req.Login, req.Password); err != nil {
|
|
return nil, fmt.Errorf("invalid creds: %w", err)
|
|
}
|
|
|
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10)
|
|
if err != nil {
|
|
logger.Error(ctx, "[register] failed to generate password hash", logger.Err(err))
|
|
return nil, fmt.Errorf("failed to generate password hash: %w", err)
|
|
}
|
|
|
|
userID, err := uuid.NewV7()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to generate user id: %w", err)
|
|
}
|
|
|
|
user := &models.User{
|
|
ID: userID,
|
|
Username: req.Login,
|
|
Login: req.Login,
|
|
PasswordHash: passwordHash,
|
|
}
|
|
|
|
err = d.authStorage.AddUser(ctx, userID, user.Login, user.Username, user.PasswordHash)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to add new user: %w", err)
|
|
}
|
|
|
|
sessionCreatedAt := time.Now()
|
|
sessionExpiredAt := sessionCreatedAt.Add(time.Hour * 24 * 7)
|
|
|
|
sessionToken, err := generateSessionToken(100)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to generate a session token: %w", err)
|
|
}
|
|
w.SetCookie(sessionTokenCookie, sessionToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, true)
|
|
|
|
csrfToken, err := generateSessionToken(100)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to generate a csrf token: %w", err)
|
|
}
|
|
w.SetCookie(csrfTokenCookie, csrfToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, false)
|
|
|
|
sessionID, err := uuid.NewV7()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to generate session id: %w", err)
|
|
}
|
|
|
|
if _, err = d.authStorage.AddSession(ctx, &models.Session{
|
|
ID: sessionID,
|
|
SessionToken: sessionToken,
|
|
CsrfToken: csrfToken,
|
|
UserID: user.ID,
|
|
CreatedAt: sessionCreatedAt,
|
|
ExpiredAt: sessionExpiredAt,
|
|
}); err != nil {
|
|
return nil, fmt.Errorf("failed to save session: %w", err)
|
|
}
|
|
|
|
return &domain.RegisterResponse{
|
|
Ok: true,
|
|
}, nil
|
|
}
|
|
|