From e1d7b4e20b5daead3c5371203f7b9e97982b66cc Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 29 Mar 2025 13:22:39 +0800 Subject: [PATCH] :recycle: Rebuilt the otp system with cache --- pkg/internal/gap/server.go | 2 +- pkg/internal/services/factors.go | 50 ++++++++++++-------------------- 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/pkg/internal/gap/server.go b/pkg/internal/gap/server.go index a1a5b7a..931f1b7 100644 --- a/pkg/internal/gap/server.go +++ b/pkg/internal/gap/server.go @@ -26,7 +26,7 @@ var ( ) const ( - FactorOtpPrefix = "otp." + FactorOtpPrefix = "auth-otp" ) func InitializeToNexus() error { diff --git a/pkg/internal/services/factors.go b/pkg/internal/services/factors.go index dc373a6..a25aff2 100644 --- a/pkg/internal/services/factors.go +++ b/pkg/internal/services/factors.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "git.solsynth.dev/hypernet/nexus/pkg/nex/cachekit" "git.solsynth.dev/hypernet/nexus/pkg/nex/localize" "git.solsynth.dev/hypernet/passport/pkg/authkit/models" @@ -12,7 +13,6 @@ import ( "git.solsynth.dev/hypernet/passport/pkg/internal/gap" "git.solsynth.dev/hypernet/pusher/pkg/pushkit" "github.com/google/uuid" - "github.com/nats-io/nats.go" "github.com/pquerna/otp/totp" "github.com/rs/zerolog/log" "github.com/samber/lo" @@ -68,12 +68,12 @@ func GetFactorCode(factor models.AuthFactor, ip string) (bool, error) { secret := uuid.NewString()[:6] - identifier := fmt.Sprintf("%s%d", gap.FactorOtpPrefix, factor.ID) - _, err := gap.Jt.Publish(identifier, []byte(secret)) + identifier := fmt.Sprintf("%s#%d", gap.FactorOtpPrefix, factor.ID) + err := cachekit.Set(gap.Ca, identifier, secret, time.Minute*30, fmt.Sprintf("user#%d", factor.AccountID)) if err != nil { - return true, fmt.Errorf("error during publish message: %v", err) + return true, fmt.Errorf("error during creating otp: %v", err) } else { - log.Info().Uint("factor", factor.ID).Str("secret", secret).Msg("Published one-time-password to JetStream...") + log.Info().Uint("factor", factor.ID).Str("secret", secret).Msg("Created one-time-password in cache...") } err = NewNotification(models.Notification{ @@ -99,12 +99,12 @@ func GetFactorCode(factor models.AuthFactor, ip string) (bool, error) { secret := uuid.NewString()[:6] - identifier := fmt.Sprintf("%s%d", gap.FactorOtpPrefix, factor.ID) - _, err := gap.Jt.Publish(identifier, []byte(secret)) + identifier := fmt.Sprintf("%s#%d", gap.FactorOtpPrefix, factor.ID) + err := cachekit.Set(gap.Ca, identifier, secret, time.Minute*30, fmt.Sprintf("user#%d", factor.AccountID)) if err != nil { - return true, fmt.Errorf("error during publish message: %v", err) + return true, fmt.Errorf("error during creating otp: %v", err) } else { - log.Info().Uint("factor", factor.ID).Str("secret", secret).Msg("Published one-time-password to JetStream...") + log.Info().Uint("factor", factor.ID).Str("secret", secret).Msg("Created one-time-password in cache...") } subject := fmt.Sprintf("[%s] %s", viper.GetString("name"), localize.L.GetLocalizedString("subjectLoginOneTimePassword", user.Language)) @@ -149,33 +149,21 @@ func CheckFactor(factor models.AuthFactor, code string) error { ) case models.InAppNotifyFactor: case models.EmailPasswordFactor: - identifier := fmt.Sprintf("%s%d", gap.FactorOtpPrefix, factor.ID) - sub, err := gap.Jt.PullSubscribe(identifier, "otp_validator", nats.BindStream("OTPs")) - if err != nil { - log.Error().Err(err).Msg("Error subscribing to subject when validating factor code...") - return fmt.Errorf("error subscribing to subject: %v", err) - } - defer sub.Unsubscribe() - - msgs, err := sub.Fetch(1, nats.MaxWait(3*time.Second)) + identifier := fmt.Sprintf("%s#%d", gap.FactorOtpPrefix, factor.ID) + val, err := cachekit.Get[string](gap.Ca, identifier) if err != nil { log.Error().Err(err).Msg("Error fetching message when validating factor code...") - return fmt.Errorf("error fetching message: %v", err) + return fmt.Errorf("one-time-password not found or expired") } - if len(msgs) > 0 { - msg := msgs[0] - if !strings.EqualFold(code, string(msg.Data)) { - return fmt.Errorf("invalid verification code") - } - log.Info().Uint("factor", factor.ID).Str("secret", code).Msg("Verified one-time-password...") - if err := msg.AckSync(); err != nil { - log.Warn().Err(err).Uint("factor", factor.ID).Msg("Failed to acknowledge message when validating factor code...") - } - return nil + if !strings.EqualFold(code, val) { + return fmt.Errorf("invalid verification code") } - - return fmt.Errorf("one-time-password not found or expired") + log.Info().Uint("factor", factor.ID).Str("secret", code).Msg("Verified one-time-password...") + if err := cachekit.Delete(gap.Ca, identifier); err != nil { + log.Error().Err(err).Msg("Error deleting the otp from cache...") + } + return nil } return nil