LIKE 过滤器转义修复:日志搜索含 %/_ 的输入不再被当通配符;pkg/util 新增 EscapeLike 共享助手 + 单测

Result: {"status":"keep","total_issues":8,"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":106,"tsc_errors":0,"vitest_failed":0,"vitest_total":126}
This commit is contained in:
ryan
2026-08-26 10:41:56 +08:00
parent 63007fc8c7
commit 2cb339258c
7 changed files with 74 additions and 12 deletions
@@ -8,6 +8,7 @@ import (
"strings"
analyticsmodel "github.com/Rain-kl/Wavelet/internal/model/analytics"
"github.com/Rain-kl/Wavelet/pkg/util"
)
const userAccessLogFilterClauseCapacity = 4
@@ -32,7 +33,7 @@ func buildUserAccessLogFilterClause(filter AccessLogFilter) (string, []any, bool
}
if trimmed := strings.TrimSpace(filter.Path); trimmed != "" {
parts = append(parts, "path LIKE ?")
args = append(args, "%"+trimmed+"%")
args = append(args, "%"+util.EscapeLike(trimmed)+"%")
}
if filter.StartTime != nil {
parts = append(parts, "created_at >= ?")
@@ -8,6 +8,7 @@ import (
"strings"
analyticsmodel "github.com/Rain-kl/Wavelet/internal/model/analytics"
"github.com/Rain-kl/Wavelet/pkg/util"
)
const (
@@ -37,7 +38,7 @@ func buildNodeAccessLogFilterClause(filter NodeAccessLogFilter) (string, []any)
}
if trimmed := normalizeNodeAccessLogRemoteAddr(filter.RemoteAddr); trimmed != "" {
parts = append(parts, "remote_addr LIKE ?")
args = append(args, trimmed+"%")
args = append(args, util.EscapeLike(trimmed)+"%")
}
hosts := normalizeNodeAccessLogHosts(filter.Hosts)
if len(hosts) > 0 {
@@ -49,11 +50,11 @@ func buildNodeAccessLogFilterClause(filter NodeAccessLogFilter) (string, []any)
parts = append(parts, "lowerUTF8(trim(host)) IN ("+strings.Join(placeholders, ", ")+")")
} else if trimmed := strings.TrimSpace(filter.Host); trimmed != "" {
parts = append(parts, "host LIKE ?")
args = append(args, trimmed+"%")
args = append(args, util.EscapeLike(trimmed)+"%")
}
if trimmed := strings.TrimSpace(filter.Path); trimmed != "" {
parts = append(parts, "path LIKE ?")
args = append(args, trimmed+"%")
args = append(args, util.EscapeLike(trimmed)+"%")
}
if filter.StatusCode > 0 {
parts = append(parts, "status_code = ?")
@@ -16,6 +16,7 @@ import (
"github.com/Rain-kl/Wavelet/internal/infra/persistence/idgen"
"github.com/Rain-kl/Wavelet/internal/model"
analyticsmodel "github.com/Rain-kl/Wavelet/internal/model/analytics"
"github.com/Rain-kl/Wavelet/pkg/util"
"gorm.io/gorm"
)
@@ -823,20 +824,20 @@ func buildNodeAccessLogFilterParts(f analyticsmodel.NodeAccessLogFilter) (string
args = append(args, nodeID)
}
if remoteAddr := strings.TrimSpace(f.RemoteAddr); remoteAddr != "" {
parts = append(parts, "remote_addr LIKE ?")
args = append(args, remoteAddr+"%")
parts = append(parts, `remote_addr LIKE ? ESCAPE '\'`)
args = append(args, util.EscapeLike(remoteAddr)+"%")
}
hosts := normalizeNodeAccessLogHosts(f.Hosts)
if len(hosts) > 0 {
parts = append(parts, "lower(trim(host)) IN ?")
args = append(args, hosts)
} else if host := strings.TrimSpace(f.Host); host != "" {
parts = append(parts, "host LIKE ?")
args = append(args, host+"%")
parts = append(parts, `host LIKE ? ESCAPE '\'`)
args = append(args, util.EscapeLike(host)+"%")
}
if path := strings.TrimSpace(f.Path); path != "" {
parts = append(parts, "path LIKE ?")
args = append(args, path+"%")
parts = append(parts, `path LIKE ? ESCAPE '\'`)
args = append(args, util.EscapeLike(path)+"%")
}
if f.StatusCode > 0 {
parts = append(parts, "status_code = ?")
@@ -1495,8 +1496,8 @@ func buildUserAccessLogWhere(filter analyticsmodel.AccessLogFilter) (string, []a
args = append(args, filter.UserIDs)
}
if trimmed := strings.TrimSpace(filter.Path); trimmed != "" {
parts = append(parts, "path LIKE ?")
args = append(args, "%"+trimmed+"%")
parts = append(parts, `path LIKE ? ESCAPE '\'`)
args = append(args, "%"+util.EscapeLike(trimmed)+"%")
}
if filter.StartTime != nil {
parts = append(parts, "created_at >= ?")