package useCases import ( "RenewCMS/internal/domain/apikey" "RenewCMS/internal/domain/audit" "RenewCMS/internal/domain/hash" "RenewCMS/internal/domain/user" "context" "time" ) type ResetPasswordUseCase struct { userRepository user.Repository hasher hash.Hasher apiKeys apikey.Repository now func() time.Time recorder audit.Recorder } func NewResetPasswordUseCase(userRepository user.Repository, hasher hash.Hasher, apiKeys apikey.Repository, now func() time.Time, recorder audit.Recorder) *ResetPasswordUseCase { return &ResetPasswordUseCase{userRepository, hasher, apiKeys, now, recorder} } func (r *ResetPasswordUseCase) ResetPassword(ctx context.Context, email string, code string, newPassword string) error { dbUser, err := r.userRepository.GetByEmail(email) if err != nil { return user.ErrInvalidPasswordResetCode } if dbUser.PasswordResetCode == "" || r.hasher.Compare(dbUser.PasswordResetCode, code) != nil { return user.ErrInvalidPasswordResetCode } if r.now().After(dbUser.PasswordResetExpiration) { return user.ErrPasswordResetCodeExpired } hashedPassword, err := r.hasher.Hash(newPassword) if err != nil { return err } if _, err = r.userRepository.ResetPassword(dbUser.ID, hashedPassword); err != nil { return err } if err := r.apiKeys.RevokeAllByUser(dbUser.ID, r.now()); err != nil { return err } event := audit.NewEvent(audit.ActionPasswordResetDone, audit.CategoryAuth) event.Actor = audit.UserActor(dbUser) event.Security = true r.recorder.Record(ctx, event) return nil }