mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-11 17:56:37 +08:00
fix lint
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package waf defines shared error messages for WAF management.
|
||||
package waf
|
||||
|
||||
const (
|
||||
errWAFRuleGroupNotFound = "WAF 规则组不存在"
|
||||
errWAFIPGroupNotFound = "IP 组不存在"
|
||||
)
|
||||
|
||||
@@ -95,7 +95,7 @@ func syncOpenFlareWAFIPGroup(ctx context.Context, group *model.OpenFlareWAFIPGro
|
||||
}
|
||||
|
||||
func syncIPGroupSubscription(ctx context.Context, group *model.OpenFlareWAFIPGroup, now time.Time) (*IPGroupSyncResult, error) {
|
||||
content, err := downloadIPGroupSubscription(group.SubscriptionURL)
|
||||
content, err := downloadIPGroupSubscription(ctx, group.SubscriptionURL)
|
||||
if err != nil {
|
||||
recordIPGroupSyncFailure(ctx, group, now, err)
|
||||
return nil, err
|
||||
@@ -266,7 +266,7 @@ func evaluateParsedIPGroupAutoConfig(ctx context.Context, config ipGroupAutoConf
|
||||
if item.StatusCode >= 400 && item.StatusCode < 500 {
|
||||
acc.clientErrorCount++
|
||||
}
|
||||
if item.StatusCode >= 500 {
|
||||
if item.StatusCode >= http.StatusInternalServerError {
|
||||
acc.serverErrorCount++
|
||||
}
|
||||
if hostIsIPLiteral(item.Host) {
|
||||
@@ -341,16 +341,20 @@ func hostIsIPLiteral(value string) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
func downloadIPGroupSubscription(rawURL string) ([]byte, error) {
|
||||
func downloadIPGroupSubscription(ctx context.Context, rawURL string) ([]byte, error) {
|
||||
if err := validateSubscriptionURL(rawURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client := http.Client{Timeout: 15 * time.Second}
|
||||
resp, err := client.Get(rawURL)
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", rawURL, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("下载订阅失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("下载订阅失败: %w", err)
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return nil, fmt.Errorf("订阅返回状态码 %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
@@ -8,10 +8,8 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -38,6 +36,9 @@ const (
|
||||
defaultWAFIPGroupAutoLookbackMinutes = 60
|
||||
minWAFIPGroupSyncIntervalMinutes = 5
|
||||
maxWAFIPGroupSyncIntervalMinutes = 43200
|
||||
|
||||
minPoWSessionTTLSeconds = 60
|
||||
minPoWChallengeTTLSeconds = 30
|
||||
)
|
||||
|
||||
// RuleGroupInput is the create/update payload for WAF rule groups.
|
||||
@@ -986,82 +987,34 @@ func defaultPoWConfig() PoWConfig {
|
||||
}
|
||||
|
||||
func normalizePoWConfig(enabled bool, raw string) (PoWConfig, error) {
|
||||
if !enabled {
|
||||
return defaultPoWConfig(), nil
|
||||
cfg, err := parsePoWConfigRaw(enabled, raw)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
cfg := defaultPoWConfig()
|
||||
text := strings.TrimSpace(raw)
|
||||
if text != "" && text != "{}" {
|
||||
if err := json.Unmarshal([]byte(text), &cfg); err != nil {
|
||||
return cfg, errors.New("pow_config 格式无效")
|
||||
}
|
||||
if err := validatePoWCoreSettings(cfg); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
if cfg.Difficulty < 1 || cfg.Difficulty > 16 {
|
||||
return cfg, errors.New("pow_config.difficulty 必须在 1-16 之间")
|
||||
if err := validatePoWCIDRs(cfg.Whitelist.IPCidrs, "白名单"); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
if !powAlgorithmValues[cfg.Algorithm] {
|
||||
return cfg, errors.New("pow_config.algorithm 必须为 fast 或 slow")
|
||||
if err := validatePoWCIDRs(cfg.Blacklist.IPCidrs, "黑名单"); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
if cfg.SessionTTL < 60 {
|
||||
return cfg, errors.New("pow_config.session_ttl 不能小于 60 秒")
|
||||
if err := validatePoWPathRegexes(cfg.Whitelist.PathRegexes, "白名单"); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
if cfg.ChallengeTTL < 30 {
|
||||
return cfg, errors.New("pow_config.challenge_ttl 不能小于 30 秒")
|
||||
if err := validatePoWPathRegexes(cfg.Blacklist.PathRegexes, "黑名单"); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
for _, cidr := range cfg.Whitelist.IPCidrs {
|
||||
if _, _, err := net.ParseCIDR(cidr); err != nil {
|
||||
return cfg, fmt.Errorf("pow_config 白名单 IP CIDR 格式无效: %s", cidr)
|
||||
}
|
||||
if err := validatePoWIPs(cfg.Whitelist.IPs, "白名单"); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
for _, cidr := range cfg.Blacklist.IPCidrs {
|
||||
if _, _, err := net.ParseCIDR(cidr); err != nil {
|
||||
return cfg, fmt.Errorf("pow_config 黑名单 IP CIDR 格式无效: %s", cidr)
|
||||
}
|
||||
if err := validatePoWIPs(cfg.Blacklist.IPs, "黑名单"); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
for _, re := range cfg.Whitelist.PathRegexes {
|
||||
if _, err := regexp.Compile(re); err != nil {
|
||||
return cfg, fmt.Errorf("pow_config 白名单路径正则格式无效: %s", re)
|
||||
}
|
||||
if err := validatePoWListMutualExclusion(cfg); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
for _, re := range cfg.Blacklist.PathRegexes {
|
||||
if _, err := regexp.Compile(re); err != nil {
|
||||
return cfg, fmt.Errorf("pow_config 黑名单路径正则格式无效: %s", re)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ip := range cfg.Whitelist.IPs {
|
||||
if net.ParseIP(ip) == nil {
|
||||
return cfg, fmt.Errorf("pow_config 白名单 IP 格式无效: %s", ip)
|
||||
}
|
||||
}
|
||||
for _, ip := range cfg.Blacklist.IPs {
|
||||
if net.ParseIP(ip) == nil {
|
||||
return cfg, fmt.Errorf("pow_config 黑名单 IP 格式无效: %s", ip)
|
||||
}
|
||||
}
|
||||
|
||||
type dimension struct {
|
||||
name string
|
||||
wl []string
|
||||
bl []string
|
||||
}
|
||||
dimensions := []dimension{
|
||||
{"IP", cfg.Whitelist.IPs, cfg.Blacklist.IPs},
|
||||
{"IP CIDR", cfg.Whitelist.IPCidrs, cfg.Blacklist.IPCidrs},
|
||||
{"路径", cfg.Whitelist.Paths, cfg.Blacklist.Paths},
|
||||
{"路径正则", cfg.Whitelist.PathRegexes, cfg.Blacklist.PathRegexes},
|
||||
{"User-Agent", cfg.Whitelist.UserAgents, cfg.Blacklist.UserAgents},
|
||||
}
|
||||
for _, dim := range dimensions {
|
||||
if len(dim.wl) > 0 && len(dim.bl) > 0 {
|
||||
return cfg, fmt.Errorf("pow_config %s 不能同时配置白名单和黑名单", dim.name)
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
@@ -1111,11 +1064,11 @@ func parseIPGroupAutoConfig(raw json.RawMessage) (ipGroupAutoConfig, error) {
|
||||
if config.LookbackMinutes <= 0 {
|
||||
config.LookbackMinutes = defaultWAFIPGroupAutoLookbackMinutes
|
||||
}
|
||||
if config.LookbackMinutes < 5 {
|
||||
config.LookbackMinutes = 5
|
||||
if config.LookbackMinutes < minWAFIPGroupSyncIntervalMinutes {
|
||||
config.LookbackMinutes = minWAFIPGroupSyncIntervalMinutes
|
||||
}
|
||||
if config.LookbackMinutes > 43200 {
|
||||
config.LookbackMinutes = 43200
|
||||
if config.LookbackMinutes > maxWAFIPGroupSyncIntervalMinutes {
|
||||
config.LookbackMinutes = maxWAFIPGroupSyncIntervalMinutes
|
||||
}
|
||||
if config.TTL == 0 {
|
||||
config.TTL = -1
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package waf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parsePoWConfigRaw(enabled bool, raw string) (PoWConfig, error) {
|
||||
if !enabled {
|
||||
return defaultPoWConfig(), nil
|
||||
}
|
||||
cfg := defaultPoWConfig()
|
||||
text := strings.TrimSpace(raw)
|
||||
if text == "" || text == "{}" {
|
||||
return cfg, nil
|
||||
}
|
||||
if err := json.Unmarshal([]byte(text), &cfg); err != nil {
|
||||
return cfg, errors.New("pow_config 格式无效")
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func validatePoWCoreSettings(cfg PoWConfig) error {
|
||||
if cfg.Difficulty < 1 || cfg.Difficulty > 16 {
|
||||
return errors.New("pow_config.difficulty 必须在 1-16 之间")
|
||||
}
|
||||
if !powAlgorithmValues[cfg.Algorithm] {
|
||||
return errors.New("pow_config.algorithm 必须为 fast 或 slow")
|
||||
}
|
||||
if cfg.SessionTTL < minPoWSessionTTLSeconds {
|
||||
return errors.New("pow_config.session_ttl 不能小于 60 秒")
|
||||
}
|
||||
if cfg.ChallengeTTL < minPoWChallengeTTLSeconds {
|
||||
return errors.New("pow_config.challenge_ttl 不能小于 30 秒")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePoWCIDRs(cidrs []string, listName string) error {
|
||||
for _, cidr := range cidrs {
|
||||
if _, _, err := net.ParseCIDR(cidr); err != nil {
|
||||
return fmt.Errorf("pow_config %s IP CIDR 格式无效: %s", listName, cidr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePoWPathRegexes(regexes []string, listName string) error {
|
||||
for _, re := range regexes {
|
||||
if _, err := regexp.Compile(re); err != nil {
|
||||
return fmt.Errorf("pow_config %s路径正则格式无效: %s", listName, re)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePoWIPs(ips []string, listName string) error {
|
||||
for _, ip := range ips {
|
||||
if net.ParseIP(ip) == nil {
|
||||
return fmt.Errorf("pow_config %s IP 格式无效: %s", listName, ip)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePoWListMutualExclusion(cfg PoWConfig) error {
|
||||
type dimension struct {
|
||||
name string
|
||||
wl []string
|
||||
bl []string
|
||||
}
|
||||
dimensions := []dimension{
|
||||
{"IP", cfg.Whitelist.IPs, cfg.Blacklist.IPs},
|
||||
{"IP CIDR", cfg.Whitelist.IPCidrs, cfg.Blacklist.IPCidrs},
|
||||
{"路径", cfg.Whitelist.Paths, cfg.Blacklist.Paths},
|
||||
{"路径正则", cfg.Whitelist.PathRegexes, cfg.Blacklist.PathRegexes},
|
||||
{"User-Agent", cfg.Whitelist.UserAgents, cfg.Blacklist.UserAgents},
|
||||
}
|
||||
for _, dim := range dimensions {
|
||||
if len(dim.wl) > 0 && len(dim.bl) > 0 {
|
||||
return fmt.Errorf("pow_config %s 不能同时配置白名单和黑名单", dim.name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user