Files
nhost/services/auth/go/controller/sign_up_email_password.go

159 lines
4.7 KiB
Go

package controller
import (
"context"
"fmt"
"log/slog"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
oapimw "github.com/nhost/nhost/internal/lib/oapi/middleware"
"github.com/nhost/nhost/services/auth/go/api"
"github.com/nhost/nhost/services/auth/go/sql"
)
func (ctrl *Controller) postSignupEmailPasswordValidateRequest(
ctx context.Context, req api.SignUpEmailPasswordRequestObject, logger *slog.Logger,
) (api.SignUpEmailPasswordRequestObject, *APIError) {
if ctrl.config.DisableSignup {
logger.WarnContext(ctx, "signup disabled")
return api.SignUpEmailPasswordRequestObject{}, ErrSignupDisabled
}
if err := ctrl.wf.ValidateSignupEmail(ctx, req.Body.Email, logger); err != nil {
return api.SignUpEmailPasswordRequestObject{}, err
}
if err := ctrl.wf.ValidatePassword(ctx, req.Body.Password, logger); err != nil {
return api.SignUpEmailPasswordRequestObject{}, err
}
options, err := ctrl.wf.ValidateSignUpOptions(
ctx, req.Body.Options, string(req.Body.Email), logger,
)
if err != nil {
return api.SignUpEmailPasswordRequestObject{}, err
}
req.Body.Options = options
return req, nil
}
func (ctrl *Controller) SignUpEmailPassword( //nolint:ireturn
ctx context.Context,
req api.SignUpEmailPasswordRequestObject,
) (api.SignUpEmailPasswordResponseObject, error) {
logger := oapimw.LoggerFromContext(ctx).With(slog.String("email", string(req.Body.Email)))
req, apiError := ctrl.postSignupEmailPasswordValidateRequest(ctx, req, logger)
if apiError != nil {
return ctrl.respondWithError(apiError), nil
}
hashedPassword, err := hashPassword(req.Body.Password)
if err != nil {
logger.ErrorContext(ctx, "error hashing password", logError(err))
return ctrl.sendError(ErrInternalServerError), nil
}
session, apiErr := ctrl.wf.SignupUserWithFn(
ctx,
string(req.Body.Email),
req.Body.Options,
true,
ctrl.postSignupEmailPasswordWithSession(
ctx, string(req.Body.Email), hashedPassword, req.Body.Options,
),
ctrl.postSignupEmailPasswordWithoutSession(
ctx, string(req.Body.Email), hashedPassword, req.Body.Options,
),
logger,
)
if apiErr != nil {
return ctrl.sendError(apiErr), nil
}
return api.SignUpEmailPassword200JSONResponse{Session: session}, nil
}
func (ctrl *Controller) postSignupEmailPasswordWithSession(
ctx context.Context,
email string,
hashedPassword string,
options *api.SignUpOptions,
) databaseWithSessionFn {
return func(
refreshTokenHash pgtype.Text,
refreshTokenExpiresAt pgtype.Timestamptz,
metadata []byte,
gravatarURL string,
) (uuid.UUID, uuid.UUID, error) {
resp, err := ctrl.wf.db.InsertUserWithRefreshToken(
ctx, sql.InsertUserWithRefreshTokenParams{
Disabled: ctrl.config.DisableNewUsers,
DisplayName: deptr(options.DisplayName),
AvatarUrl: gravatarURL,
Email: sql.Text(email),
PasswordHash: sql.Text(hashedPassword),
Ticket: pgtype.Text{}, //nolint:exhaustruct
TicketExpiresAt: sql.TimestampTz(time.Now()),
EmailVerified: false,
Locale: deptr(options.Locale),
DefaultRole: deptr(options.DefaultRole),
Metadata: metadata,
Roles: deptr(options.AllowedRoles),
IsAnonymous: false,
RefreshTokenHash: refreshTokenHash,
RefreshTokenExpiresAt: refreshTokenExpiresAt,
},
)
if err != nil {
return uuid.Nil, uuid.Nil,
fmt.Errorf("error inserting user with refresh token: %w", err)
}
return resp.ID, resp.RefreshTokenID, nil
}
}
func (ctrl *Controller) postSignupEmailPasswordWithoutSession(
ctx context.Context,
email string,
hashedPassword string,
options *api.SignUpOptions,
) databaseWithoutSessionFn {
return func(
ticket pgtype.Text,
ticketExpiresAt pgtype.Timestamptz,
metadata []byte,
gravatarURL string,
) error {
_, err := ctrl.wf.db.InsertUser(ctx, sql.InsertUserParams{
ID: uuid.New(),
Disabled: ctrl.config.DisableNewUsers,
DisplayName: deptr(options.DisplayName),
AvatarUrl: gravatarURL,
Email: sql.Text(email),
PasswordHash: sql.Text(hashedPassword),
Ticket: ticket,
TicketExpiresAt: ticketExpiresAt,
EmailVerified: false,
Locale: deptr(options.Locale),
DefaultRole: deptr(options.DefaultRole),
Metadata: metadata,
Roles: deptr(options.AllowedRoles),
PhoneNumber: pgtype.Text{}, //nolint:exhaustruct
Otp: "",
OtpHashExpiresAt: pgtype.Timestamptz{}, //nolint:exhaustruct
OtpMethodLastUsed: pgtype.Text{}, //nolint:exhaustruct
})
if err != nil {
return fmt.Errorf("error inserting user: %w", err)
}
return nil
}
}