diff --git a/backend/internal/services/auth.go b/backend/internal/services/auth.go index cf8676e..5e5c21e 100644 --- a/backend/internal/services/auth.go +++ b/backend/internal/services/auth.go @@ -68,7 +68,7 @@ func NewAuthService(_log *zap.Logger, _dbctx database.DbContext, _redis *redis.C // FIXME: review possible problems due to a large pipeline request pipe := _redis.Pipeline() for _, guid := range guids { - if err := pipe.Set(ctx, fmt.Sprint("session:%s:is_terminated", guid), true, 0); err != nil { + if err := pipe.Set(ctx, fmt.Sprintf("session::%s::is_terminated", guid), true, 0); err != nil { panic("Failed to cache terminated session: " + err.Err().Error()) } } @@ -95,7 +95,25 @@ func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequ defer helper.RollbackOnError(err) - // TODO: check occupation with redis + if isInProgress, err := a.redis.Get( + context.TODO(), + fmt.Sprintf("email::%s::registration_in_progress", + request.Email), + ).Bool(); err != nil { + if err != redis.Nil { + a.log.Error( + "Failed to look up cached registration_in_progress state of email as part of registration procedure", + zap.String("email", request.Email), + zap.Error(err)) + return false, errs.ErrServerError + } + isInProgress = false + } else if isInProgress { + a.log.Warn( + "Attempted to begin registration on email that is in progress of registration or on cooldown", + zap.String("email", request.Email)) + return false, errs.ErrTooManyRequests + } if occupationStatus, err = db.TXQueries.CheckUserRegistrationAvailability(db.CTX, database.CheckUserRegistrationAvailabilityParams{ Email: request.Email, @@ -118,7 +136,19 @@ func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequ } else if occupationStatus.EmailBusy { // Falsely confirm in order to avoid disclosing registered email addresses - // TODO: save this email into redis + if err := a.redis.Set( + context.TODO(), + fmt.Sprintf("email::%s::registration_in_progress", request.Email), + true, + time.Duration(10 * time.Minute), // XXX: magic number + ).Err(); err != nil { + a.log.Error( + "Failed to falsely set cache registration_in_progress state for email as a measure to prevent email enumeration", + zap.String("email", request.Email), + zap.Error(err)) + return false, errs.ErrServerError + } + a.log.Warn( "Attempted registration for a taken email", zap.String("email", request.Email), @@ -211,6 +241,19 @@ func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequ zap.String("code", generatedCode)) } + if err := a.redis.Set( + context.TODO(), + fmt.Sprintf("email::%s::registration_in_progress", request.Email), + true, + time.Duration(10 * time.Minute), // XXX: magic number + ).Err(); err != nil { + a.log.Error( + "Failed to cache registration_in_progress state for email", + zap.String("email", request.Email), + zap.Error(err)) + return false, errs.ErrServerError + } + if err = helper.Commit(); err != nil { a.log.Error( "Failed to commit transaction",