From acbc75e2bdb9db8899ce800de9f59b710f62b429 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Sun, 12 Jul 2026 09:59:28 -0700 Subject: [PATCH] fix(util): reject invalid characters between time-estimate units (#38416) (#38423) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport #38416 by @TowyTowy ### What / why `TimeEstimateParse` (used by the issue time-estimate form) only checked that the first token starts at the beginning of the string and the last token ends at its end, but never checked the gaps between consecutive tokens. Non-whitespace garbage embedded between two valid units was silently dropped and the string accepted with a wrong value instead of being reported as invalid. Examples that were wrongly accepted before this change: - `1h 2x 3m` → 3780s (parsed as 1h3m) - `1h_2m` → 3720s - `1h,1m` → 3660s All three now return an "invalid time string" error, while valid inputs such as `1h 1m 1s` and `1h1m1s` keep working. ### How Reject any non-whitespace content between two matched units. Signed-off-by: TowyTowy Signed-off-by: wxiaoguang Co-authored-by: TowyTowy <85077986+TowyTowy@users.noreply.github.com> Co-authored-by: wxiaoguang --- modules/util/time_str.go | 7 +++++++ modules/util/time_str_test.go | 3 +++ 2 files changed, 10 insertions(+) diff --git a/modules/util/time_str.go b/modules/util/time_str.go index 81b132c3db3..c498e6ebe13 100644 --- a/modules/util/time_str.go +++ b/modules/util/time_str.go @@ -40,6 +40,7 @@ var timeStrGlobalVars = sync.OnceValue(func() *timeStrGlobalVarsType { }) func TimeEstimateParse(timeStr string) (int64, error) { + timeStr = strings.TrimSpace(timeStr) if timeStr == "" { return 0, nil } @@ -51,7 +52,13 @@ func TimeEstimateParse(timeStr string) (int64, error) { if matches[0][0] != 0 || matches[len(matches)-1][1] != len(timeStr) { return 0, fmt.Errorf("invalid time string: %s", timeStr) } + prevEnd := 0 for _, match := range matches { + // only whitespace may separate two units, otherwise the string contains invalid content like "1h x 2m" + if strings.TrimSpace(timeStr[prevEnd:match[0]]) != "" { + return 0, fmt.Errorf("invalid time string: %s", timeStr) + } + prevEnd = match[1] amount, err := strconv.ParseInt(timeStr[match[2]:match[3]], 10, 64) if err != nil { return 0, fmt.Errorf("invalid time string: %v", err) diff --git a/modules/util/time_str_test.go b/modules/util/time_str_test.go index 8d1de51c8e6..4efe902bee5 100644 --- a/modules/util/time_str_test.go +++ b/modules/util/time_str_test.go @@ -22,6 +22,9 @@ func TestTimeStr(t *testing.T) { {"1s", 1, false}, {"1h 1m 1s", 3600 + 60 + 1, false}, {"1d1x", 0, true}, + {"1h 2x 3m", 0, true}, + {"1h_2m", 0, true}, + {"1h,1m", 0, true}, } for _, test := range tests { t.Run(test.input, func(t *testing.T) {