package auth import ( "context" "fmt" "time" "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/svc" "github.com/redis/go-redis/v9" "go.uber.org/zap" ) func registerIpLimit(svcCtx *svc.ServiceContext, ctx context.Context, registerIp, authType, account string) (isOk bool) { if !svcCtx.Config.Register.EnableIpRegisterLimit { return true } // Add timeout protection for Redis operations ctx, cancel := context.WithTimeout(ctx, 2*time.Second) defer cancel() // Use a sorted set to track IP registrations with timestamp as score // Key format: register:ip:{ip} key := fmt.Sprintf("%s%s", config.RegisterIpKeyPrefix, registerIp) now := time.Now().Unix() expiration := int64(svcCtx.Config.Register.IpRegisterLimitDuration) * 60 // Clean up expired entries first (remove entries older than expiration duration) expireTimestamp := now - expiration removed, err := svcCtx.Redis.ZRemRangeByScore(ctx, key, "0", fmt.Sprintf("%d", expireTimestamp)).Result() if err != nil { zap.S().Errorf("[registerIpLimit] ZRemRangeByScore Err: %v", err) return true } if removed > 0 { zap.S().Debugf("[registerIpLimit] Cleaned %d expired entries for IP: %s", removed, registerIp) } // Get current count of registrations within the time window count, err := svcCtx.Redis.ZCard(ctx, key).Result() if err != nil { zap.S().Errorf("[registerIpLimit] ZCard Err: %v", err) return true } // Check if limit is reached if count >= svcCtx.Config.Register.IpRegisterLimit { zap.S().Warnf("[registerIpLimit] IP %s exceeded limit: %d/%d", registerIp, count, svcCtx.Config.Register.IpRegisterLimit) return false } // Add new registration entry with current timestamp as score member := fmt.Sprintf("%s:%s", authType, account) if err := svcCtx.Redis.ZAdd(ctx, key, redis.Z{ Score: float64(now), Member: member, }).Err(); err != nil { zap.S().Errorf("[registerIpLimit] ZAdd Err: %v", err) return true } // Set expiration on the sorted set key if err := svcCtx.Redis.Expire(ctx, key, time.Minute*time.Duration(svcCtx.Config.Register.IpRegisterLimitDuration)).Err(); err != nil { zap.S().Errorf("[registerIpLimit] Expire Err: %v", err) } return true }