diff --git a/frontend/app/(main)/waf/components/ip-group-dialog.tsx b/frontend/app/(main)/waf/components/ip-group-dialog.tsx index 972c0101..a5d685c6 100644 --- a/frontend/app/(main)/waf/components/ip-group-dialog.tsx +++ b/frontend/app/(main)/waf/components/ip-group-dialog.tsx @@ -153,13 +153,16 @@ function appendAutomaticPresetRule( ? `${config.lookback_minutes}m` : '1h'; // strip legacy field so saved JSON only keeps lookback duration string - const { lookback_minutes: _legacyLookbackMinutes, ...rest } = config; + const { + lookback_minutes: _legacyLookbackMinutes, + lookback: _existingLookback, + ...rest + } = config; return JSON.stringify( { - lookback, - ttl: typeof rest.ttl === 'number' ? rest.ttl : -1, ...rest, lookback, + ttl: typeof rest.ttl === 'number' ? rest.ttl : -1, rules: nextRules, }, null, diff --git a/internal/apps/openflare/waf/ip_group_sync.go b/internal/apps/openflare/waf/ip_group_sync.go index 40ccfd95..e49342c5 100644 --- a/internal/apps/openflare/waf/ip_group_sync.go +++ b/internal/apps/openflare/waf/ip_group_sync.go @@ -54,6 +54,8 @@ func (env ipGroupAutoRuleEnv) StatusRatio(code any) float64 { return float64(countStatusMatches(env.statusCounts, code)) / float64(env.RequestCount) } +const maxHTTPStatusCodeDigits = 999 + // countStatusMatches sums status counts for an exact code or class token. // Accepted forms: // - int / int64 / float64: exact status code (e.g. 404) @@ -66,31 +68,13 @@ func countStatusMatches(statusCounts map[int]int, code any) int { switch v := code.(type) { case int: return statusCounts[v] - case int8: - return statusCounts[int(v)] - case int16: - return statusCounts[int(v)] - case int32: - return statusCounts[int(v)] case int64: - return statusCounts[int(v)] - case uint: - return statusCounts[int(v)] - case uint8: - return statusCounts[int(v)] - case uint16: - return statusCounts[int(v)] - case uint32: - return statusCounts[int(v)] - case uint64: - return statusCounts[int(v)] - case float32: - if v != float32(int(v)) { + if v < 0 || v > int64(maxHTTPStatusCodeDigits) { return 0 } return statusCounts[int(v)] case float64: - if v != float64(int(v)) { + if v != float64(int64(v)) || v < 0 || v > float64(maxHTTPStatusCodeDigits) { return 0 } return statusCounts[int(v)] @@ -127,14 +111,10 @@ func countStatusMatchesString(statusCounts map[int]int, raw string) int { return 0 } code = code*10 + int(ch-'0') - if code > 999 { + if code > maxHTTPStatusCodeDigits { return 0 } } - if code < 100 || code > 599 { - // still allow lookup for non-standard codes if present - return statusCounts[code] - } return statusCounts[code] } diff --git a/pkg/render/openresty/render.go b/pkg/render/openresty/render.go index 6b6770f0..c30bda28 100644 --- a/pkg/render/openresty/render.go +++ b/pkg/render/openresty/render.go @@ -911,6 +911,12 @@ func buildPathExactMatchPattern(rules []string) string { return fmt.Sprintf("^(?:%s)$", strings.Join(parts, "|")) } +const ( + limitReqDefaultBurst = 5 + limitReqPerSecondBurstMul = 2 + limitReqPerMinuteBurstDiv = 5 +) + func calculateBurst(rateStr string) int { rateStr = strings.ToLower(strings.TrimSpace(rateStr)) if rateStr == "" { @@ -919,20 +925,19 @@ func calculateBurst(rateStr string) int { var val int var unit string _, err := fmt.Sscanf(rateStr, "%dr/%s", &val, &unit) - if err != nil { - return 5 + if err != nil || val <= 0 { + return limitReqDefaultBurst } - if val <= 0 { - return 5 - } - if unit == "s" { - return val * 2 - } else if unit == "m" { - b := val / 5 - if b < 5 { - b = 5 + switch unit { + case "s": + return val * limitReqPerSecondBurstMul + case "m": + b := val / limitReqPerMinuteBurstDiv + if b < limitReqDefaultBurst { + return limitReqDefaultBurst } return b + default: + return limitReqDefaultBurst } - return 5 }