package controllers import ( "context" "database/sql" "errors" "time" "gitea.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/hash" "gitea.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/logger" "gitea.badhouseplants.net/softplayer/softplayer-backend/internal/repository" "github.com/google/uuid" "github.com/redis/go-redis/v9" ) var ( ErrEmailUsed = errors.New("email is already used") ErrUserNotFound = errors.New("user not found") ErrWrongPassword = errors.New("wrong password") ) type AccountController struct { DB *sql.DB Redis *redis.Client DevMode bool HashCost int16 AccessTokenTTL time.Duration RefreshTokenTTL time.Duration JWTSecret []byte } type JWT struct { RefreshToken string AccessToken string } type AccountParams struct{} type AccountData struct { Password string Email string UUID string } // Create a new account func (c *AccountController) Create(ctx context.Context, data *AccountData) (string, error) { log := logger.FromContext(ctx).WithValues("email", data.Email) log.V(2).Info("Creating a user") data.UUID = uuid.New().String() passwordHash, err := hash.HashPassword(data.Password, int(c.HashCost)) if err != nil { log.Error(err, "Couldn't crate the password hash") return "", ErrServerError } queryData := &repository.AccountData{ UUID: data.UUID, Email: data.Email, PasswordHash: passwordHash, } if err := repository.CreateAccount(ctx, c.DB, queryData); err != nil { if errors.Is(err, repository.ErrAlreadyExists) { return "", ErrEmailUsed } log.Error(err, "Couldn't create a user") return "", ErrServerError } return data.UUID, nil } // Login into an existing account (check password and email) func (c *AccountController) Login(ctx context.Context, email, password string) (string, error) { log := logger.FromContext(ctx).WithValues("email", email) log.V(2).Info("Trying to verify user login") passwordHash, err := repository.GetPasswordHashForEmail(ctx, c.DB, email) if err != nil { if errors.Is(err, repository.ErrNotFound) { return "", ErrUserNotFound } log.Error(err, "Couldn't get the password hash") return "", ErrServerError } if err := hash.CheckPasswordHash(password, passwordHash); err != nil { return "", ErrWrongPassword } uuid, err := repository.GetUUIDForEmail(ctx, c.DB, email) if err != nil { if errors.Is(err, repository.ErrNotFound) { return "", ErrUserNotFound } log.Error(err, "Couldn't get tha password hash") return "", ErrServerError } return uuid, nil }